Joe
Joe

Reputation: 13091

Python Flask - how to run subprocess (pass a command)?

I have a running Flask app but want to pass any command via URL and make flask execute it on a host server and return results.

e.g. when running curl localhost:5000/run/"ls -l" (command is ls -l) -> expecting result:

.
..
file1
file2
etc..

So far I have:

import os

from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello():
    return "Hello World!"

@app.route('/run/<command>')
def run(command):
   return 'Run this %s!' % command


if __name__ == "__main__":  
    app.run(debug = True)

Thanks.

Upvotes: 0

Views: 14259

Answers (2)

constt
constt

Reputation: 2320

I suggest to pass commands in a JSON request instead of sending them as URL parameters:

from subprocess import Popen, TimeoutExpired, PIPE

from flask import Flask, jsonify, abort, request

app = Flask(__name__)

@app.route("/", methods=["POST"])
def index():
    req_json = request.get_json()

    if req_json is None or "command" not in req_json:
        abort(400, description="Please provide command in JSON request!")

    proc = Popen(req_json["command"], stdout=PIPE, stderr=PIPE, shell=True)

    try:
        outs, errs = proc.communicate(timeout=1)
    except TimeoutExpired:
        proc.kill()
        abort(500, description="The timeout is expired!")

    if errs:
        abort(500, description=errs.decode('utf-8'))

    return jsonify(success=True, message=outs.decode('utf-8'))

@app.errorhandler(400)
def bad_request(error):
    return jsonify(success=False, message=error.description), 400

@app.errorhandler(500)
def server_error(error):
    return jsonify(success=False, message=error.description) , 500

Save it to, say server.py, and run it:

$ FLASK_APP=server.py:app flask run
 * Serving Flask app "server.py:app"
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

Request example:

$ curl -X POST -H "Content-Type: application/json" -d '{"command": "ls -l"}' localhost:5000
{"message":"total 8\ndrwxr-xr-x 2 const const 4096 Jul 19 09:52 __pycache__\n-rw-rw-r-- 1 const const 1043 Jul 19 09:52 server.py\n","success":true}

Upvotes: 0

Joe
Joe

Reputation: 13091

Just made it to work:

import os

from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello():
    return "Hello World!"


@app.route('/run/<command>')
def run(command):
   out = os.popen(command).read()
   return (out)


if __name__ == "__main__":  
    app.run(debug = True)

Upvotes: 3

Related Questions