Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

Subprocess and os.Popen in django not running under apache with mod_wsgi at Linux Fedora30

Ask Question

I have problem to run Os.Popen and subprocess in django under apache server of linux fedora30

when I deploy django app on apache I can't run below command in linux with django under apache:

command2 = "[ -f /home/mohammad/file_sharing.txt ] || echo 'server IP: '%s'\n\nPath File:'%s'\n\nMount Point:'%s  > /home/mohammad/file_sharing.txt " %(IP_Server_File_Sharing,Path_File_Sharing,Mount_Point) 
            k = os.popen(command2)
            command1 = "[ -f /home/mohammad/file_sharing.txt ] && echo 'server IP: '%s'\n\nPath File:'%s'\n\nMount Point:'%s > /home/mohammad/file_sharing.txt " %(IP_Server_File_Sharing,Path_File_Sharing,Mount_Point) 
            k1 = os.popen(command1)

These are all jobs that do :

1. I use Fedora30

2. Then install and update yum and other packeges such below command:

yum update

sudo systemctl stop firewalld.service

yum install python-pip python-devel python3-pip python3-devel

pip3 install --upgrade pip

pip3 install virtualenv

dnf install httpd

yum install python3-mod_wsgi.x86_64

3. Then make a directory and install Django on virtual env:

mkdir /home/mohammad/myweb1
cd myweb1
virtualenv venv
source venv/bin/activate

4. Then pip install below packages:

asgiref==3.3.1

Django==3.1.5

psycopg2-binary==2.8.6

python-pam==1.8.4

pytz==2020.5

sqlparse==0.4.1

5. Then config other settings of django :

django-admin startproject myproject
cd myproject
python manage.py startapp main
python manage.py collectstatic
python manage.py makemigrations
python manage.py migrate

6. now config settings.py

After these 5 steps I configure settings.py in django:

ALLOWED_HOSTS = ['*']

STATIC_ROOT ='/home/mohammad/myweb1/myproject/main/static/'

7. apache config which make django.conf file in in /etc/httpd/conf.d/ and named django.conf

   <VirtualHost *:80>
    Alias /static /home/mohammad/myweb1/myproject/main/static
    <Directory /home/mohammad/myweb1/myproject/main/static>
            Require all granted
    </Directory>
    <Directory /home/mohammad/myweb1/myproject/myproject>
            <Files wsgi.py>
                    Require all granted
            </Files>
    </Directory>
    WSGIApplicationGroup %{GLOBAL}
    WSGIDaemonProcess myproject python-path=/home/mohammad/myweb1/myproject python- 
    home=/home/mohammad/myweb1/venv
    WSGIProcessGroup myproject
    WSGIScriptAlias / /home/mohammad/myweb1/myproject/myproject/wsgi.py
   </VirtualHost>

8. finally I run below command:

setendorce 0

chown -R apache:apache /home/mohammad/myweb1

usermod -a -G mohammad apache

chmode -R 710 /home/mohammad

9. view.py packages:

from django.conf.urls import url
from django.shortcuts import render , get_object_or_404 , redirect
from django.urls.base import resolve
from . models import Main
from django.contrib.auth import authenticate , login, logout  , views
from django.http import HttpResponseRedirect
from django.urls import reverse 
# import ntplib
from django.contrib.auth.models import User
from datetime import datetime,timezone
from time import ctime , sleep
import pam
import datetime
import os
import subprocess , shlex ,tempfile
from subprocess import Popen
import re
from subprocess import STDOUT , check_output , PIPE
import random
import logging
import subprocess
import io
import collections

10. view.py code of def def file_sharing(request):

if request.method == "POST":
        IP_Server_File_Sharing = request.POST.get('IP_Server_File_Sharing')
        Path_File_Sharing = request.POST.get('Path_File_Sharing')
        Mount_Point = request.POST.get('Mount_Point')
        IP = re.compile("^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$")
        Pathfile = re.compile("^(/[^/ ]*)+/?$")
        MountPoint = re.compile("^(/[^/ ]*)+/?$")
        tf_IP = bool(IP.fullmatch(str(IP_Server_File_Sharing)))
        tf_Pathfile = bool(Pathfile.fullmatch(str(Path_File_Sharing)))
        tf_MountPoint= bool(Pathfile.fullmatch(str(Mount_Point)))
        if IP_Server_File_Sharing=="" and Path_File_Sharing=="" and Mount_Point=="" :
            ### Create the logger
            logger = logging.getLogger('User empty file_sharing field and make error')
            logger.setLevel(logging.DEBUG)
            ### Setup the console handler with a StringIO object
            log_capture_string = io.StringIO()
            ch = logging.StreamHandler(log_capture_string)
            ch.setLevel(logging.DEBUG)
            ### Optionally add a formatter
            formatter = logging.Formatter('%(asctime)s - %(message)s ')
            ch.setFormatter(formatter)
            ### Add the console handler to the logger
            logger.addHandler(ch)
            ### Send log messages. 
            # logger.debug('debug message')
            logger.info('User empty file_sharing field and make error')
            # logger.warn('warn message')
            # logger.error('error message')
            # logger.critical('critical message')
            ### Pull the contents back into a string and close the stream
            log_contents = log_capture_string.getvalue()
            # log_capture_string.close()
            ### Output as lower case to prove it worked. 
            print(log_contents)
            b = Main( log1 = log_contents)
            b.save()
            error = "هیچ فیلدی را خالی نگذارید!!!"
            return render(request , 'front/error.html' , {'error':error})
        if tf_IP and tf_Pathfile  and  tf_MountPoint \
        and IP_Server_File_Sharing!="" and Path_File_Sharing!="" and Mount_Point!="" :
            command2 = "[ -f /home/mohammad/file_sharing.txt ] || echo 'server IP: '%s'\n\nPath File:'%s'\n\nMount Point:'%s  > /home/mohammad/file_sharing.txt " %(IP_Server_File_Sharing,Path_File_Sharing,Mount_Point) 
            k = os.popen(command2)
            command1 = "[ -f /home/mohammad/file_sharing.txt ] && echo 'server IP: '%s'\n\nPath File:'%s'\n\nMount Point:'%s > /home/mohammad/file_sharing.txt " %(IP_Server_File_Sharing,Path_File_Sharing,Mount_Point) 
            k1 = os.popen(command1)
            sleep(10)
            command_show= "echo 'server IP: '%s'\nPath File:'%s'\nMount Point:'%s " %(IP_Server_File_Sharing,Path_File_Sharing,Mount_Point)
            l = os.popen(command_show)
            show = l.read()
            print('-------------\n', show)
            ### Create the logger
            logger = logging.getLogger('System overwrite file_sharing data in file_sharing.txt')
            logger.setLevel(logging.DEBUG)
            ### Setup the console handler with a StringIO object
            log_capture_string = io.StringIO()
            ch = logging.StreamHandler(log_capture_string)
            ch.setLevel(logging.DEBUG)
            ### Optionally add a formatter
            formatter = logging.Formatter('%(asctime)s - %(message)s ')
            ch.setFormatter(formatter)
            ### Add the console handler to the logger
            logger.addHandler(ch)
            ### Send log messages. 
            # logger.debug('debug message')
            logger.info('System overwrite file_sharing data in file_sharing.txt ')
            # logger.warn('warn message')
            # logger.error('error message')
            # logger.critical('critical message')
            ### Pull the contents back into a string and close the stream
            log_contents = log_capture_string.getvalue()
            # log_capture_string.close()
            ### Output as lower case to prove it worked. 
            print(log_contents)
            b = Main( log1 = log_contents)
            b.save()
            return render(request , 'front/File_sharing.html' , {'show':show} )
        if not tf_IP or not tf_Pathfile or  not tf_MountPoint:
            ### Create the logger
            logger = logging.getLogger('One of the field in file sharing page is not math by pattern')
            logger.setLevel(logging.DEBUG)
            ### Setup the console handler with a StringIO object
            log_capture_string = io.StringIO()
            ch = logging.StreamHandler(log_capture_string)
            ch.setLevel(logging.DEBUG)
            ### Optionally add a formatter
            formatter = logging.Formatter('%(asctime)s - %(message)s ')
            ch.setFormatter(formatter)
            ### Add the console handler to the logger
            logger.addHandler(ch)
            ### Send log messages. 
            # logger.debug('debug message')
            logger.info('One of the field in file sharing page is not math by pattern')
            # logger.warn('warn message')
            # logger.error('error message')
            # logger.critical('critical message')
            ### Pull the contents back into a string and close the stream
            log_contents = log_capture_string.getvalue()
            # log_capture_string.close()
            ### Output as lower case to prove it worked. 
            print(log_contents)
            b = Main( log1 = log_contents)
            b.save()
            error = "تمام فیلد را را به درستی تکمیل کنید"
            return render(request , 'front/error.html' , {'error':error})
    return render(request , 'front/File_sharing.html' )

11. html code of this project in template directory:

   {% extends 'front/master.html'%}
   {% load static %}
   {% block mainblock %}
<div class="box box-danger">
          <form  role="form" method="POST" action="{% url 'file_sharing' %}">
         {% csrf_token %}
        <div class="box-header with-border" style="direction:ltr;"><i class="fa fa-fw fa-chevron-circle-right"></i>
          <h3 class="box-title">File Sharing</h3>
        <div class="box-body" >
          <div class="row">
            <div class="col-xs-4" style="direction:ltr;">
              <input id="IP_Server_File_Sharing" name="IP_Server_File_Sharing" type="text" class="form-control" placeholder="192.168.0.0" required>
            <div class="col-xs-4" style="direction:ltr;">
              <input id="Path_File_Sharing" name="Path_File_Sharing" type="text" class="form-control" placeholder="Path File Sharing" required>
            <div class="col-xs-4" style="direction:ltr;">
              <input id="Mount_Point" name="Mount_Point" type="text" class="form-control" placeholder="Mount Point" required>
          <div style="direction:ltr;">
            <textarea class="form-control" rows="3" placeholder="output">{{show}}</textarea>
          <button  name="x" value="Submit" type="submit" id="myButton" class="btn btn-primary">ارسال اطلاعات</button>
          </form>
        <!-- /.box-body -->
      {% endblock %}

And the logs of apache in /var/log/httpd are:

sudo: a terminal is required to read the password; either use the -S option to read from standard input or configure an askpass helper
[Fri Jan 08 19:44:44.013574 2021] [wsgi:error] [pid 5258:tid 139771201857280] [remote 127.0.0.1:46632] ----------------------- 
[Fri Jan 08 19:49:01.449617 2021] [wsgi:error] [pid 5258:tid 139771201857280] [remote 127.0.0.1:46664] ---------------- None
[Fri Jan 08 19:49:01.449656 2021] [wsgi:error] [pid 5258:tid 139771201857280] [remote 127.0.0.1:46664]  optionsRadios =============  None
/bin/sh: line 4: /home/mohammad/file_sharing.txt: Permission denied
[Fri Jan 08 19:49:31.631038 2021] [wsgi:error] [pid 5258:tid 139771201857280] [remote 127.0.0.1:46674] -------------
[Fri Jan 08 19:49:31.631148 2021] [wsgi:error] [pid 5258:tid 139771201857280] [remote 127.0.0.1:46674]  server IP: 127.0.0.2
[Fri Jan 08 19:49:31.631164 2021] [wsgi:error] [pid 5258:tid 139771201857280] [remote 127.0.0.1:46674] Path File:/home/
[Fri Jan 08 19:49:31.631170 2021] [wsgi:error] [pid 5258:tid 139771201857280] [remote 127.0.0.1:46674] Mount Point:/ali/
[Fri Jan 08 19:49:31.631181 2021] [wsgi:error] [pid 5258:tid 139771201857280] [remote 127.0.0.1:46674] 
[Fri Jan 08 19:49:31.631901 2021] [wsgi:error] [pid 5258:tid 139771201857280] [remote 127.0.0.1:46674] System overwrite file_sharing data in file_sharing.txt INFO     System overwrite file_sharing data in file_sharing.txt 
[Fri Jan 08 19:49:31.631995 2021] [wsgi:error] [pid 5258:tid 139771201857280] [remote 127.0.0.1:46674] 2021-01-08 19:49:31,631 - System overwrite file_sharing data in file_sharing.txt  
[Fri Jan 08 19:49:31.632003 2021] [wsgi:error] [pid 5258:tid 139771201857280] [remote 127.0.0.1:46674] 

Attention these logs are costumized logs that I append to Datebase (postgresql):

[Fri Jan 08 19:44:44.013574 2021] [wsgi:error] [pid 5258:tid 139771201857280] [remote 127.0.0.1:46632] ----------------------- 
    [Fri Jan 08 19:49:01.449617 2021] [wsgi:error] [pid 5258:tid 139771201857280] [remote 127.0.0.1:46664] ---------------- None
    [Fri Jan 08 19:49:01.449656 2021] [wsgi:error] [pid 5258:tid 139771201857280] [remote 127.0.0.1:46664]  optionsRadios =============  None
[Fri Jan 08 19:49:31.631038 2021] [wsgi:error] [pid 5258:tid 139771201857280] [remote 127.0.0.1:46674] -------------
    [Fri Jan 08 19:49:31.631148 2021] [wsgi:error] [pid 5258:tid 139771201857280] [remote 127.0.0.1:46674]  server IP: 127.0.0.2
    [Fri Jan 08 19:49:31.631164 2021] [wsgi:error] [pid 5258:tid 139771201857280] [remote 127.0.0.1:46674] Path File:/home/
    [Fri Jan 08 19:49:31.631170 2021] [wsgi:error] [pid 5258:tid 139771201857280] [remote 127.0.0.1:46674] Mount Point:/ali/
    [Fri Jan 08 19:49:31.631181 2021] [wsgi:error] [pid 5258:tid 139771201857280] [remote 127.0.0.1:46674] 
    [Fri Jan 08 19:49:31.631901 2021] [wsgi:error] [pid 5258:tid 139771201857280] [remote 127.0.0.1:46674] System overwrite file_sharing data in file_sharing.txt INFO     System overwrite file_sharing data in file_sharing.txt 
    [Fri Jan 08 19:49:31.631995 2021] [wsgi:error] [pid 5258:tid 139771201857280] [remote 127.0.0.1:46674] 2021-01-08 19:49:31,631 - System overwrite file_sharing data in file_sharing.txt  
    [Fri Jan 08 19:49:31.632003 2021] [wsgi:error] [pid 5258:tid 139771201857280] [remote 127.0.0.1:46674] 

finally can any one help me to solve this problem?

I need to run Os.popen and subprocess in django under apache at linux fedora30

can I solve this problem by enable shell_exec? how? Or how can sovle Permission denied that apache access to run my linux command?

Hello and welcome to the community Amirmohammad !

Your question is too verbose, It would be enough to bring the necessary block of code and also your wsgi configuration and just tell the commands that you executed for the permission in this case.

Anyway. You are using mod_wsgi for running your Django application. So I suggest to define ServerName directive (I've name that localhost here) and pass that as a WSGIProcessGroup and it's good to specify user=username directive.

You can edit the mod_wsgi config file in this way:

    WSGIDaemonProcess localhost python-path=/home/mohammad/myweb1/myproject  user=mohammad
    WSGIProcessGroup localhost
  <VirtualHost *:80>
        ServerName localhost
        ServerAlias localhost
        DocumentRoot /home/mohammad/myweb1/myproject/
        <Directory /home/mohammad/myweb1/myproject/main/static>
            Require all granted
        </Directory>
        <Directory /home/mohammad/myweb1/myproject/myproject>
            <Files wsgi.py>
                    Require all granted
            </Files>
        </Directory>
         WSGIDaemonProcess localhost python-path=/home/mohammad/myweb1/myproject  user=mohammad
    WSGIProcessGroup localhost
         Alias /static /home/mohammad/myweb1/myproject/main/static
         WSGIScriptAlias / /home/mohammad/myweb1/myproject/myproject/wsgi.py
  </VirtualHost>

In such a way, you don't have to chown the file to apache user. It would be your home user (mohammad).

Also you need to run popen with close_fds=True argument to prevent file descriptor inheritance (the Unix topic) .

I discover the issue... Due to apache not running as root, it can't run my command I can solve this problem by use paramiko lib and ssh up to root , but this is not a common way and great solution. – Mohammad Jan 20, 2021 at 16:41

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.