0

I am developing an app that runs (always - it is a controller for a heat pump system) in python and I use flask to provide a user interface to controll the app.

The flask app has different control items, for instance buttons to turn the system on or off.

I am trying to execute a specific function from a python module in response to a "click" on a button (the final goal is to change a value in an mmap resource that will be read in another module to change the state of the system).

In the flask app I have something like:

    @app.route('/cntr_hpauto',methods=['GET','POST'])
    @basic_auth.required
    def cntr_hpauto():
        manage_globals.set_from_web()
        return render_template('control.html',cur_hp_mode="auto")

However, this generates an "internal server error'

The complete flask app is (manage_globals is the *.py file I want to import and that contains the function I want to call):

from flask import Flask, request, render_template
from flask_basicauth import BasicAuth

import sys
import os
import mmap
import manage_globals

app = Flask(__name__)

app.config['BASIC_AUTH_USERNAME'] = '***'
app.config['BASIC_AUTH_PASSWORD'] = '***'

basic_auth = BasicAuth(app)

@app.route('/')

def splash():
        return render_template('splash.html')

@app.route('/dashboard', methods=['GET','POST'])
@basic_auth.required
def dashboard():
        return render_template('dashboard.html')

@app.route('/control',methods=['GET','POST'])
@basic_auth.required
def control():
    return render_template('control.html',cur_hp_mode="none")

@app.route('/cntr_hpauto',methods=['GET','POST'])
@basic_auth.required
def cntr_hpauto():
    manage_globals.set_from_web()
    return render_template('control.html',cur_hp_mode="auto")

@app.route('/cntr_hpon',methods=['GET','POST'])
@basic_auth.required
def cntr_hpon():
    return render_template('control.html',cur_hp_mode="on")

@app.route('/cntr_hpoff',methods=['GET','POST'])
@basic_auth.required
def cntr_hpoff():
    return render_template('control.html',cur_hp_mode="off")

if __name__ == '__main__':
    app.run(ssl_context=('/home/groenhol/certs/groenhol.pem', '/home/groenhol/certs/groenhol.key'))

And the module (example, only writing the map file to a logfile) is:

# 14/08/2017 henk witte / groenholland
# part of geotech project, ann controller dual source heat pump
# this module maintains the global database with mmap

import mmap

""" the mmap file is position dependent!
use readlines and split

    line 1: heatpump auto/on/off
    line 2: userpump off
    line 3: srcselect air
"""
def init_conf_file():
    dummy="a"

def set_from_web():
    with open("geotech.conf", "r+b") as f:
        mm = mmap.mmap(f.fileno(), 0)
        for line in iter(mm.readline, b''):
            with open("globals.log","ab") as f2:
                f2.write(line)
    f2.close()
    mm.close()

if __name__ == '__main__':
    init_conf_file()

The flask app runs fine without the function call, the module I import by itself runs fine as well.

Any help much appreciated!

Henk

As suggested by Kevin Pasquarella I added app.debug = true. However, as the error occurs when apache is loadin the main splash page already (apache server error) this did not help. But I then looked at the apache error log:

[Tue Aug 15 21:33:14.638580 2017] [mpm_event:notice] [pid 959:tid 3067240448] AH00489: Apache/2.4.18 (Ubuntu) OpenSSL/1.0.2g mod_wsgi/4.5.17 Python/3.4 configured -- resuming normal operations
[Tue Aug 15 21:33:14.639152 2017] [core:notice] [pid 959:tid 3067240448] AH00094: Command line: '/usr/sbin/apache2'
[Tue Aug 15 21:33:19.825211 2017] [wsgi:error] [pid 2461:tid 3031819312] [remote 192.168.178.85:9676] mod_wsgi (pid=2461): Target WSGI script '/home/groenhol/py_control/ui/webapp/main.wsgi' cannot be loaded as Python module.
[Tue Aug 15 21:33:19.826502 2017] [wsgi:error] [pid 2461:tid 3031819312] [remote 192.168.178.85:9676] mod_wsgi (pid=2461): Exception occurred processing WSGI script '/home/groenhol/py_control/ui/webapp/main.wsgi'.
[Tue Aug 15 21:33:19.967421 2017] [wsgi:error] [pid 2461:tid 3031819312] [remote 192.168.178.85:9676] Traceback (most recent call last):
[Tue Aug 15 21:33:19.970377 2017] [wsgi:error] [pid 2461:tid 3031819312] [remote 192.168.178.85:9676]   File "/home/groenhol/py_control/ui/webapp/main.wsgi", line 4, in <module>
[Tue Aug 15 21:33:19.970581 2017] [wsgi:error] [pid 2461:tid 3031819312] [remote 192.168.178.85:9676]     from main import app as application
[Tue Aug 15 21:33:19.971031 2017] [wsgi:error] [pid 2461:tid 3031819312] [remote 192.168.178.85:9676]   File "/home/groenhol/py_control/ui/webapp/main.py", line 41

I then searched for mod_wsgi cannot be loaded as python module

Answers indicate there is a difference between the python version I am using (3.4) and the wsgi version.

So I checked the wsgi version in /etc/apache2/mods-enabled/mod-wsgi.load:

LoadModule wsgi_module "/home/groenhol/miniconda3/lib/python3.4/site-packages/mod_wsgi/server/mod_wsgi-py34.cpython-34m.so" WSGIPythonHome "/home/groenhol/miniconda3"

So seems to use python 3.4 version.

To make sure I use ldd as I found during the search:

groenhol@arm:~/mod_wsgi-4.5.15$ ldd LoadModule wsgi_module "/home/groenhol/miniconda3/lib/python3.4/site-packages/mod_wsgi/server/mod_wsgi-py34.cpython-34m.so"
LoadModule:
ldd: ./LoadModule: No such file or directory
wsgi_module:
ldd: ./wsgi_module: No such file or directory
/home/groenhol/miniconda3/lib/python3.4/site-packages/mod_wsgi/server/mod_wsgi-py34.cpython-34m.so:
        linux-vdso.so.1 =>  (0xbee90000)
        libpython3.4m.so.1.0 => /home/groenhol/miniconda3/lib/libpython3.4m.so.1.0 (0xb6d40000)
        libpthread.so.0 => /lib/arm-linux-gnueabihf/libpthread.so.0 (0xb6d0f000)
        libc.so.6 => /lib/arm-linux-gnueabihf/libc.so.6 (0xb6c23000)
        /lib/ld-linux-armhf.so.3 (0x7f64d000)
        libdl.so.2 => /lib/arm-linux-gnueabihf/libdl.so.2 (0xb6c10000)
        libutil.so.1 => /lib/arm-linux-gnueabihf/libutil.so.1 (0xb6bfd000)
        libm.so.6 => /lib/arm-linux-gnueabihf/libm.so.6 (0xb6b85000)
        libgcc_s.so.1 => /lib/arm-linux-gnueabihf/libgcc_s.so.1 (0xb6b5c000)
groenhol@arm:~/mod_wsgi-4.5.15$ WSGIPythonHome "/home/groenhol/miniconda3"
-bash: WSGIPythonHome: command not found

As far as I can tell (http://modwsgi.readthedocs.io/en/develop/user-guides/checking-your-installation.html#python-shared-library) this seems OK?

Ok, so next step?

Graham Dumpleton
  • 57,726
  • 6
  • 119
  • 134
henkwitte
  • 11
  • 1
  • 3
  • 3
    in your app file, under `if __name__ == '__main__': app.run(...)`, add `app.debug = True` so you can get a traceback of the error and where it's coming from, and add it to the post – Kevin Pasquarella Aug 14 '17 at 21:16
  • it looks like there's an error here from the traceback: `from main import app as application` – Kevin Pasquarella Aug 15 '17 at 20:18
  • Perhaps, but the error only occurs when I try to call a function from a *.py module that i import. Seems only flask functions work in this context. The module itself runs fine when i execute it, it just cannot be called from the flask main.py and throws the wsgi fault when apache loads the pages/app. – henkwitte Aug 15 '17 at 21:48
  • So far I found as possible problem either python version that wsgi was compiled against is different and a remark about supposedly needing to run in virtual python environment. – henkwitte Aug 15 '17 at 21:49
  • hm. what happens when you run the app locally? and yes, running a virtual environment will help with dependency and version issues – Kevin Pasquarella Aug 16 '17 at 12:51
  • you may find something useful in this thread: https://stackoverflow.com/questions/31252791/flask-importerror-no-module-named-flask – Kevin Pasquarella Aug 16 '17 at 17:59
  • You should have run ``ldd /home/groenhol/miniconda3/lib/python3.4/site-packages/mod_wsgi/server/mod_wsgi-py34.cpython-34m.so``. Don't include the ``LoadModule wsgi_module`` as argument to ``ldd``, only the path of the ``.so`` file. – Graham Dumpleton Aug 17 '17 at 00:07

2 Answers2

0

The code:

def set_from_web():
    with open("geotech.conf", "r+b") as f:
        mm = mmap.mmap(f.fileno(), 0)
        for line in iter(mm.readline, b''):
            with open("globals.log","ab") as f2:
                f2.write(line)
    f2.close()
    mm.close()

is going to be a problem because you are using a relative path name to files.

The current working directory of the process will not be where your code is and also will not be writable to the Apache user. You need to use absolute paths and ensure the Apache user has write permission to files.

See:

Graham Dumpleton
  • 57,726
  • 6
  • 119
  • 134
  • Thanks for that, I agree and did not think about that yet. I need to make sure this is corrected! However, to check if this was the cause of my problem I changed the function to a simpe dummy = "b" statement. When giving a reference (not calling!) this function in main.py the server throws the error on loading. – henkwitte Aug 17 '17 at 14:07
  • The problem is that you haven't included the full Python traceback from the error logs, as well as exception name and description. Unless you can provide that, can only guess what is source of the error. – Graham Dumpleton Aug 17 '17 at 21:54
0

The solution turned out to be pretty trivial: the mod_wsgi does not like if you ident by spaces and tabs. I changed all idents to tabs and then the code runs!

I found this out by changing the code to something very simple, just returning a string and printing that on the web page created by the flask template. Then I could see the wsgi fault in the apache log. In the full code other faults were occuring making it difficult to find out what exactly caused the error.

I also took care of the comment made by Graham Dumpleton (that apache cannot write to the directory), I created a shared directory (/home/py_shared) which I added to the www-data group (both the python user and apache are member of that group). I then set the group of the folder to www-data and used chmod g+w py_shared and chmod g+s py_shared to set the correct permissions.

This topic is discussed on several pages, e.g.:

https://unix.stackexchange.com/questions/154776/create-files-that-both-www-data-and-myuser-can-edit

THANKS for all your suggestions!

henkwitte
  • 11
  • 1
  • 3
  • Mixing of tabs and spaces is a general issue with Python and not specific to mod_wsgi. Problems would occur if you had overridden the editor settings to have the tab width displayed to be anything but 8 characters. Is better to set up an editor to automatically replace a tab with spaces. – Graham Dumpleton Aug 21 '17 at 22:15
  • Thanks Graham, not new to programming (c/fortran mainly) but this is my first python project and a lot of "features" to discover. – henkwitte Aug 23 '17 at 07:24