I was trying to build a web-based utility for Linux Management and I found those are not familiar to me with which Node.js, ShellJS, ... etc. Luckily I found another way to control the underlying Linux system in python, simply put, the flask web framework plus the python subprocess module would work.
Simple demo code
import subprocess
from flask import Flask
app = Flask(__name__)
def run_command(command):
return subprocess.Popen(command, shell=True, stdout=subprocess.PIPE).stdout.read()
@app.route('/')
def command_server(command):
return run_command(command)
$ export FLASK_APP=server.py
$ flask run
image.png
The subprocess module allows you to spawn new processes, connect to their input/output/error pipes, and obtain their return codes. This module intends to replace several older modules and functions
os.system
os.spawn*
Difference between Popen and os.system call
os.system is equivalent to Unix system command, while subprocess was a helper module created to provide many of the facilities provided by the Popen commands with an easier and controllable interface. Those were designed similar to the Unix Popen command.
system() executes a command specified in command by calling /bin/sh -c command, and returns after the command has been completed
The popen() function opens a process by creating a pipe, forking, and invoking the shell.
subprocess.popen vs subprocess.run
subprocess.run was added in Python 3.5 as a simplification over subprocess.Popen when you just want to execute a command and wait until it finishes, but you don't want to do anything else meanwhile. For other cases, you still need to use subprocess.Popen.
The main difference is that subprocess.run executes a command and waits for it to finish, while with subprocess.Popen you can continue doing your stuff while the process finishes and then just repeatedly call subprocess.communicate yourself to pass and receive data to your process.
Note that, what subprocess.run is actually doing is invoking for you the Popen and communicate, so you don't need to make a loop to pass/receive data nor wait for the process to finish.
Check the official documentation for information of which parameters of subprocess.run are passed to Popen and which to communicate.
Complete code demo from run shell command with flask gist
from flask import Flask
from flask import request
import subprocess
app = Flask('flaskshell')
ip_whitelist = ['192.168.1.2', '192.168.1.3']
query_success = "SELECT COUNT(*) FROM flasktest.tasks WHERE task_status='Success'"
query_pending = "SELECT COUNT(*) FROM flasktest.tasks WHERE task_status='Pending'"
query_failed = "SELECT COUNT(*) FROM flasktest.tasks WHERE task_status='Failed'"
def valid_ip():
client = request.remote_addr
if client in ip_whitelist:
return True
else:
return False
@app.route('/status/')
def get_status():
if valid_ip():
command_success = "mysql -uflaskuser -pflask123 -e '{0}'".format(
query_success)
command_pending = "mysql -uflaskuser -pflask123 -e '{0}'".format(
query_pending)
command_failed = "mysql -uflaskuser -pflask123 -e '{0}'".format(
query_failed)
try:
result_success = subprocess.check_output(
[command_success], shell=True)
result_pending = subprocess.check_output(
[command_pending], shell=True)
result_failed = subprocess.check_output(
[command_failed], shell=True)
except subprocess.CalledProcessError as e:
return "An error occurred while trying to fetch task status updates."
return 'Success %s, Pending %s, Failed %s' % (result_success, result_pending, result_failed)
else:
return """
404 Not FoundNot Found
The requested URL was not found on the server.
If you entered the URL manually please check your
spelling and try again.
""", 404if __name__ == '__main__':
app.run()