mirror of
https://github.com/akuker/RASCSI.git
synced 2024-11-26 13:49:21 +00:00
Introduce async operations in webapp (#485)
* Introduce run_async for system processes * Remove redundant code for system shutdown and reboot endpoints * Use async process with systemd_service * Modify innerHTML to show progress messages * Add docstring
This commit is contained in:
parent
a24a07508e
commit
5b397229cd
@ -14,6 +14,7 @@ from ractl_cmds import (
|
||||
list_devices,
|
||||
reserve_scsi_ids,
|
||||
)
|
||||
from pi_cmds import run_async
|
||||
from socket_cmds import send_pb_command
|
||||
from settings import CFG_DIR, CONFIG_FILE_SUFFIX, PROPERTIES_SUFFIX, RESERVATIONS
|
||||
import rascsi_interface_pb2 as proto
|
||||
@ -175,42 +176,42 @@ def unzip_file(file_name, member=False, members=False):
|
||||
members contains all of the full paths to each of the zip archive members
|
||||
Returns (dict) with (boolean) status and (list of str) msg
|
||||
"""
|
||||
from subprocess import run
|
||||
from re import escape
|
||||
from asyncio import run
|
||||
server_info = get_server_info()
|
||||
prop_flag = False
|
||||
|
||||
if not member:
|
||||
unzip_proc = run(
|
||||
["unzip", "-d", server_info["image_dir"], "-n", "-j", \
|
||||
f"{server_info['image_dir']}/{file_name}"], capture_output=True
|
||||
)
|
||||
unzip_proc = run(run_async(
|
||||
f"unzip -d {server_info['image_dir']} -n -j "
|
||||
f"{server_info['image_dir']}/{file_name}"
|
||||
))
|
||||
for path in members:
|
||||
if path.endswith(PROPERTIES_SUFFIX):
|
||||
name = PurePath(path).name
|
||||
rename_file(f"{server_info['image_dir']}/{name}", f"{CFG_DIR}/{name}")
|
||||
prop_flag = True
|
||||
else:
|
||||
unzip_proc = run(
|
||||
["unzip", "-d", server_info["image_dir"], "-n", "-j", \
|
||||
f"{server_info['image_dir']}/{file_name}", escape(member)], capture_output=True
|
||||
)
|
||||
from re import escape
|
||||
member = escape(member)
|
||||
unzip_proc = run(run_async(
|
||||
f"unzip -d {server_info['image_dir']} -n -j "
|
||||
f"{server_info['image_dir']}/{file_name} {member}"
|
||||
))
|
||||
# Attempt to unzip a properties file in the same archive dir
|
||||
unzip_prop = run(
|
||||
["unzip", "-d", CFG_DIR, "-n", "-j", \
|
||||
f"{server_info['image_dir']}/{file_name}", escape(member) + "." + PROPERTIES_SUFFIX], capture_output=False
|
||||
)
|
||||
if unzip_prop.returncode == 0:
|
||||
unzip_prop = run(run_async(
|
||||
f"unzip -d {CFG_DIR} -n -j "
|
||||
f"{server_info['image_dir']}/{file_name} {member}.{PROPERTIES_SUFFIX}"
|
||||
))
|
||||
if unzip_prop["returncode"] == 0:
|
||||
prop_flag = True
|
||||
if unzip_proc.returncode != 0:
|
||||
stderr = unzip_proc.stderr.decode("utf-8")
|
||||
logging.warning("Unzipping failed: %s", stderr)
|
||||
return {"status": False, "msg": stderr}
|
||||
if unzip_proc["returncode"] != 0:
|
||||
logging.warning("Unzipping failed: %s", unzip_proc["stderr"])
|
||||
return {"status": False, "msg": unzip_proc["stderr"]}
|
||||
|
||||
from re import findall
|
||||
unzipped = findall(
|
||||
"(?:inflating|extracting):(.+)\n",
|
||||
unzip_proc.stdout.decode("utf-8")
|
||||
unzip_proc["stdout"]
|
||||
)
|
||||
return {"status": True, "msg": unzipped, "prop_flag": prop_flag}
|
||||
|
||||
@ -404,7 +405,6 @@ def write_drive_properties(file_name, conf):
|
||||
return {"status": False, "msg": f"Could not write to file: {file_path}"}
|
||||
|
||||
|
||||
|
||||
def read_drive_properties(path_name):
|
||||
"""
|
||||
Reads drive properties from json formatted file.
|
||||
|
@ -3,6 +3,8 @@ Module for methods controlling and getting information about the Pi's Linux syst
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
import asyncio
|
||||
import logging
|
||||
from settings import AUTH_GROUP
|
||||
|
||||
|
||||
@ -11,10 +13,8 @@ def systemd_service(service, action):
|
||||
Takes (str) service and (str) action
|
||||
Action can be one of start/stop/restart
|
||||
"""
|
||||
return (
|
||||
subprocess.run(["sudo", "/bin/systemctl", action, service]).returncode
|
||||
== 0
|
||||
)
|
||||
proc = asyncio.run(run_async("sudo /bin/systemctl {action} {service}"))
|
||||
return proc["returncode"] == 0
|
||||
|
||||
|
||||
def reboot_pi():
|
||||
@ -119,6 +119,30 @@ def introspect_file(file_path, re_term):
|
||||
return False
|
||||
|
||||
|
||||
async def run_async(cmd):
|
||||
"""
|
||||
Takes (str) cmd with the shell command to execute
|
||||
Executes shell command and captures output
|
||||
Returns (dict) with (int) returncode, (str) stdout, (str) stderr
|
||||
"""
|
||||
proc = await asyncio.create_subprocess_shell(
|
||||
cmd,
|
||||
stdout=asyncio.subprocess.PIPE,
|
||||
stderr=asyncio.subprocess.PIPE)
|
||||
|
||||
stdout, stderr = await proc.communicate()
|
||||
|
||||
logging.info("Executed command \"%s\" with status code %d", cmd, proc.returncode)
|
||||
if stdout:
|
||||
stdout = stdout.decode()
|
||||
logging.info("stdout: %s", stdout)
|
||||
if stderr:
|
||||
stderr = stderr.decode()
|
||||
logging.info("stderr: %s", stderr)
|
||||
|
||||
return {"returncode": proc.returncode, "stdout": stdout, "stderr": stderr}
|
||||
|
||||
|
||||
def auth_active():
|
||||
"""
|
||||
Inspects if the group defined in AUTH_GROUP exists on the system.
|
||||
@ -132,4 +156,4 @@ def auth_active():
|
||||
"status": True,
|
||||
"msg": "You must log in to use this function!",
|
||||
}
|
||||
return {"status": False, "msg": ""}
|
||||
return {"status": False, "msg": ""}
|
@ -59,7 +59,7 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="flash">
|
||||
<div class="flash" id="flash">
|
||||
{% for category, message in get_flashed_messages(with_categories=true) %}
|
||||
{% if category == "stdout" or category == "stderr" %}
|
||||
<pre>{{ message }}</pre>
|
||||
|
@ -201,7 +201,7 @@
|
||||
<form action="/files/unzip" method="post">
|
||||
<input name="zip_file" type="hidden" value="{{ file['name'] }}">
|
||||
<input name="zip_member" type="hidden" value="{{ member }}">
|
||||
<input type="submit" value="Unzip">
|
||||
<input type="submit" value="Unzip" onclick='document.getElementById("flash").innerHTML = "<div class=\"message\">Unzipping single file...</div>"'>
|
||||
</form>
|
||||
</summary>
|
||||
<ul style="list-style: none;">
|
||||
@ -215,7 +215,7 @@
|
||||
<form action="/files/unzip" method="post">
|
||||
<input name="zip_file" type="hidden" value="{{ file['name'] }}">
|
||||
<input name="zip_member" type="hidden" value="{{ member }}">
|
||||
<input type="submit" value="Unzip">
|
||||
<input type="submit" value="Unzip" onclick='document.getElementById("flash").innerHTML = "<div class=\"message\">Unzipping single file...</div>"'>
|
||||
</form>
|
||||
{% endif %}
|
||||
</li>
|
||||
@ -243,7 +243,7 @@
|
||||
<form action="/files/unzip" method="post">
|
||||
<input name="zip_file" type="hidden" value="{{ file['name'] }}">
|
||||
<input name="zip_members" type="hidden" value="{{ file['zip_members'] }}">
|
||||
<input type="submit" value="Unzip All">
|
||||
<input type="submit" value="Unzip All" onclick='document.getElementById("flash").innerHTML = "<div class=\"message\">Unzipping all files...</div>"'>
|
||||
</form>
|
||||
{% else %}
|
||||
<form action="/scsi/attach" method="post">
|
||||
@ -388,7 +388,7 @@
|
||||
<form action="/files/download_to_images" method="post">
|
||||
<label for="url">URL:</label>
|
||||
<input name="url" placeholder="URL" required="" type="url">
|
||||
<input type="submit" value="Download">
|
||||
<input type="submit" value="Download" onclick='document.getElementById("flash").innerHTML = "<div class=\"message\">Downloading File to Images...</div>"'>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
@ -415,7 +415,7 @@
|
||||
<form action="/files/download_to_afp" method="post">
|
||||
<label for="url">URL:</label>
|
||||
<input name="url" placeholder="URL" required="" type="url">
|
||||
<input type="submit" value="Download">
|
||||
<input type="submit" value="Download" onclick='document.getElementById("flash").innerHTML = "<div class=\"message\">Downloading File to AppleShare...</div>"'>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
@ -458,7 +458,7 @@
|
||||
</select>
|
||||
<label for="url">URL:</label>
|
||||
<input name="url" placeholder="URL" required="" type="url">
|
||||
<input type="submit" value="Download and Mount ISO">
|
||||
<input type="submit" value="Download and Mount ISO" onclick='document.getElementById("flash").innerHTML = "<div class=\"message\">Downloading File as ISO...</div>"'>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -695,9 +695,6 @@ def restart():
|
||||
flash(auth["msg"], "error")
|
||||
return redirect(url_for("index"))
|
||||
|
||||
detach_all()
|
||||
flash("Safely detached all devices.")
|
||||
flash("Rebooting the Pi momentarily...")
|
||||
reboot_pi()
|
||||
return redirect(url_for("index"))
|
||||
|
||||
@ -730,9 +727,6 @@ def shutdown():
|
||||
flash(auth["msg"], "error")
|
||||
return redirect(url_for("index"))
|
||||
|
||||
detach_all()
|
||||
flash("Safely detached all devices.")
|
||||
flash("Shutting down the Pi momentarily...")
|
||||
shutdown_pi()
|
||||
return redirect(url_for("index"))
|
||||
|
||||
@ -940,7 +934,7 @@ def delete():
|
||||
@APP.route("/files/unzip", methods=["POST"])
|
||||
def unzip():
|
||||
"""
|
||||
Unzips a specified zip file
|
||||
Unzips all files in a specified zip archive, or a single file in the zip archive
|
||||
"""
|
||||
auth = auth_active()
|
||||
if auth["status"] and "username" not in session:
|
||||
|
Loading…
Reference in New Issue
Block a user