Home > Mobile >  How to run and cancel a linux command using Flask Python API?
How to run and cancel a linux command using Flask Python API?

Time:09-14

I am working on flask based python api. It has two api, run_cmd and stop_cmd. Run cmd will execute a command in the terminal. This command will keep on going until someone manually cancels it. So to cancel it, we have stop_cmd api. Below is the code:

from flask import Flask, jsonify, request
from threading import Thread  
from subprocess import call 

app = Flask(__name__)

def RunCmd():
    call('while true; do echo "hello"; sleep 2s; done', shell=True)

@app.route('/run_cmd', methods=['GET'])
def run_cmd():
    Thread(target=RunCmd).start()
    return jsonify({"status": "ok"}), 200

@app.route('/stop_cmd', methods=['GET'])
def stop_cmd():
    # This api will stop the cmd running in RunCmd

As you can see in the above code, if we hit the /run_cmd, it starts and keeps printing hello in the terminal. I wanted to know how can we cancel this ongoing session of the command so that we can write it in stop cmd api. Is this possible. Thanks

CodePudding user response:

This is how I solved it

from flask import Flask, jsonify, request
from threading import Thread  
import subprocess
import psutil
from subprocess import call 
from command_runner import command_runner


app = Flask(__name__)

proc = ""

def kill(proc_pid):
    process = psutil.Process(proc_pid)
    for proc in process.children(recursive=True):
        proc.kill()
    process.kill()

def RunCmd():
    global proc
    proc = subprocess.Popen(['while true; do echo "hello"; sleep 2s; done'], shell=True)
    

@app.route('/run_cmd', methods=['GET'])
def run_cmd():
    Thread(target=RunCmd).start()
    return jsonify({"status": "ok"}), 200

@app.route('/stop_cmd', methods=['GET'])
def stop_cmd():
    global proc
    kill(proc.pid)
    return jsonify({"status": True}), 200


if __name__ == '__main__':
    app.run(host='127.0.0.1', port=5000)

CodePudding user response:

Subprocess.call is a part of an older, deprecated API if I am informed correctly. Instead, you should probably use subprocess.Popen(). Then you could start your command by running

proc = subprocess.Popen(["somecommand", "-somearg", "somethingelse"])

This will return a Popen object which you can terminate by sending it a signal, for example proc.terminate() or proc.kill().

  • Related