mirror of
https://github.com/akuker/RASCSI.git
synced 2024-06-11 09:29:33 +00:00
0b78f09f8d
Add bridge-utils Minor fixes to easyinstall Can now save config, detach all devices Bridge script error out if any command fails
299 lines
8.8 KiB
Python
299 lines
8.8 KiB
Python
from flask import Flask, render_template, request, flash, url_for, redirect, send_file
|
|
from werkzeug.utils import secure_filename
|
|
|
|
from file_cmds import (
|
|
create_new_image,
|
|
download_file_to_iso,
|
|
delete_image,
|
|
unzip_file,
|
|
download_image,
|
|
)
|
|
from pi_cmds import shutdown_pi, reboot_pi, running_version, rascsi_service
|
|
from ractl_cmds import (
|
|
attach_image,
|
|
list_devices,
|
|
is_active,
|
|
list_files,
|
|
detach_by_id,
|
|
eject_by_id,
|
|
get_valid_scsi_ids,
|
|
attach_daynaport,
|
|
is_bridge_setup,
|
|
daynaport_setup_bridge,
|
|
list_config_files,
|
|
detach_all,
|
|
)
|
|
from settings import *
|
|
|
|
app = Flask(__name__)
|
|
|
|
|
|
@app.route("/")
|
|
def index():
|
|
devices = list_devices()
|
|
scsi_ids = get_valid_scsi_ids(devices)
|
|
return render_template(
|
|
"index.html",
|
|
bridge_configured=is_bridge_setup("eth0"),
|
|
devices=devices,
|
|
active=is_active(),
|
|
files=list_files(),
|
|
config_files=list_config_files(),
|
|
base_dir=base_dir,
|
|
scsi_ids=scsi_ids,
|
|
max_file_size=MAX_FILE_SIZE,
|
|
version=running_version(),
|
|
)
|
|
|
|
|
|
@app.route("/config/save", methods=["POST"])
|
|
def config_save():
|
|
file_name = request.form.get("name") or "default"
|
|
file_name = f"{base_dir}{file_name}.csv"
|
|
import csv
|
|
|
|
with open(file_name, "w") as csv_file:
|
|
writer = csv.writer(csv_file)
|
|
for device in list_devices():
|
|
if device["type"] is not "-":
|
|
writer.writerow(device.values())
|
|
flash(f"Saved config to {file_name}!")
|
|
return redirect(url_for("index"))
|
|
|
|
|
|
@app.route("/config/load", methods=["POST"])
|
|
def config_load():
|
|
file_name = request.form.get("name") or "default.csv"
|
|
file_name = f"{base_dir}{file_name}"
|
|
detach_all()
|
|
import csv
|
|
|
|
with open(file_name) as csv_file:
|
|
config_reader = csv.reader(csv_file)
|
|
for row in config_reader:
|
|
image_name = row[3].replace("(WRITEPROTECT)", "")
|
|
attach_image(row[0], image_name, row[2])
|
|
flash(f"Loaded config from {file_name}!")
|
|
return redirect(url_for("index"))
|
|
|
|
|
|
@app.route("/logs")
|
|
def logs():
|
|
import subprocess
|
|
|
|
lines = request.args.get("lines") or "100"
|
|
process = subprocess.run(["journalctl", "-n", lines], capture_output=True)
|
|
|
|
if process.returncode == 0:
|
|
headers = {"content-type": "text/plain"}
|
|
return process.stdout.decode("utf-8"), 200, headers
|
|
else:
|
|
flash("Failed to get logs")
|
|
flash(process.stdout.decode("utf-8"), "stdout")
|
|
flash(process.stderr.decode("utf-8"), "stderr")
|
|
return redirect(url_for("index"))
|
|
|
|
|
|
@app.route("/daynaport/attach", methods=["POST"])
|
|
def daynaport_attach():
|
|
scsi_id = request.form.get("scsi_id")
|
|
process = attach_daynaport(scsi_id)
|
|
if process.returncode == 0:
|
|
flash(f"Attached DaynaPORT to SCSI id {scsi_id}!")
|
|
return redirect(url_for("index"))
|
|
else:
|
|
flash(f"Failed to attach DaynaPORT to SCSI id {scsi_id}!", "error")
|
|
flash(process.stdout.decode("utf-8"), "stdout")
|
|
flash(process.stderr.decode("utf-8"), "stderr")
|
|
return redirect(url_for("index"))
|
|
|
|
|
|
@app.route("/daynaport/setup", methods=["POST"])
|
|
def daynaport_setup():
|
|
# Future use for wifi
|
|
interface = request.form.get("interface") or "eth0"
|
|
process = daynaport_setup_bridge(interface)
|
|
if process.returncode == 0:
|
|
flash(f"Configured DaynaPORT bridge on {interface}!")
|
|
return redirect(url_for("index"))
|
|
else:
|
|
flash(f"Failed to configure DaynaPORT bridge on {interface}!", "error")
|
|
flash(process.stdout.decode("utf-8"), "stdout")
|
|
flash(process.stderr.decode("utf-8"), "stderr")
|
|
return redirect(url_for("index"))
|
|
|
|
|
|
@app.route("/scsi/attach", methods=["POST"])
|
|
def attach():
|
|
file_name = request.form.get("file_name")
|
|
scsi_id = request.form.get("scsi_id")
|
|
|
|
# Validate image type by suffix
|
|
if file_name.lower().endswith(".iso") or file_name.lower().endswith("iso"):
|
|
image_type = "cd"
|
|
elif file_name.lower().endswith(".hda"):
|
|
image_type = "hd"
|
|
else:
|
|
flash("Unknown file type. Valid files are .iso, .hda, .cdr", "error")
|
|
return redirect(url_for("index"))
|
|
|
|
process = attach_image(scsi_id, file_name, image_type)
|
|
if process.returncode == 0:
|
|
flash(f"Attached {file_name} to SCSI id {scsi_id}!")
|
|
return redirect(url_for("index"))
|
|
else:
|
|
flash(f"Failed to attach {file_name} to SCSI id {scsi_id}!", "error")
|
|
flash(process.stdout.decode("utf-8"), "stdout")
|
|
flash(process.stderr.decode("utf-8"), "stderr")
|
|
return redirect(url_for("index"))
|
|
|
|
|
|
@app.route("/scsi/detach_all", methods=["POST"])
|
|
def detach_all_devices():
|
|
detach_all()
|
|
flash("Detached all SCSI devices!")
|
|
return redirect(url_for("index"))
|
|
|
|
|
|
@app.route("/scsi/detach", methods=["POST"])
|
|
def detach():
|
|
scsi_id = request.form.get("scsi_id")
|
|
process = detach_by_id(scsi_id)
|
|
if process.returncode == 0:
|
|
flash("Detached SCSI id " + scsi_id + "!")
|
|
return redirect(url_for("index"))
|
|
else:
|
|
flash("Failed to detach SCSI id " + scsi_id + "!", "error")
|
|
flash(process.stdout, "stdout")
|
|
flash(process.stderr, "stderr")
|
|
return redirect(url_for("index"))
|
|
|
|
|
|
@app.route("/scsi/eject", methods=["POST"])
|
|
def eject():
|
|
scsi_id = request.form.get("scsi_id")
|
|
process = eject_by_id(scsi_id)
|
|
if process.returncode == 0:
|
|
flash("Ejected scsi id " + scsi_id + "!")
|
|
return redirect(url_for("index"))
|
|
else:
|
|
flash("Failed to eject SCSI id " + scsi_id + "!", "error")
|
|
flash(process.stdout, "stdout")
|
|
flash(process.stderr, "stderr")
|
|
return redirect(url_for("index"))
|
|
|
|
|
|
@app.route("/pi/reboot", methods=["POST"])
|
|
def restart():
|
|
reboot_pi()
|
|
flash("Restarting...")
|
|
return redirect(url_for("index"))
|
|
|
|
|
|
@app.route("/rascsi/restart", methods=["POST"])
|
|
def rascsi_restart():
|
|
rascsi_service("restart")
|
|
flash("Restarting RaSCSI Service...")
|
|
return redirect(url_for("index"))
|
|
|
|
|
|
@app.route("/pi/shutdown", methods=["POST"])
|
|
def shutdown():
|
|
shutdown_pi()
|
|
flash("Shutting down...")
|
|
return redirect(url_for("index"))
|
|
|
|
|
|
@app.route("/files/download_to_iso", methods=["POST"])
|
|
def download_file():
|
|
scsi_id = request.form.get("scsi_id")
|
|
url = request.form.get("url")
|
|
process = download_file_to_iso(scsi_id, url)
|
|
if process.returncode == 0:
|
|
flash("File Downloaded")
|
|
return redirect(url_for("index"))
|
|
else:
|
|
flash("Failed to download file", "error")
|
|
flash(process.stdout, "stdout")
|
|
flash(process.stderr, "stderr")
|
|
return redirect(url_for("index"))
|
|
|
|
|
|
@app.route("/files/download_image", methods=["POST"])
|
|
def download_img():
|
|
url = request.form.get("url")
|
|
# TODO: error handling
|
|
download_image(url)
|
|
flash("File Downloaded")
|
|
return redirect(url_for("index"))
|
|
|
|
|
|
@app.route("/files/upload", methods=["POST"])
|
|
def upload_file():
|
|
if "file" not in request.files:
|
|
flash("No file part", "error")
|
|
return redirect(url_for("index"))
|
|
file = request.files["file"]
|
|
if file:
|
|
filename = secure_filename(file.filename)
|
|
file.save(os.path.join(app.config["UPLOAD_FOLDER"], filename))
|
|
return redirect(url_for("index", filename=filename))
|
|
|
|
|
|
@app.route("/files/create", methods=["POST"])
|
|
def create_file():
|
|
file_name = request.form.get("file_name")
|
|
size = request.form.get("size")
|
|
type = request.form.get("type")
|
|
|
|
process = create_new_image(file_name, type, size)
|
|
if process.returncode == 0:
|
|
flash("Drive created")
|
|
return redirect(url_for("index"))
|
|
else:
|
|
flash("Failed to create file", "error")
|
|
flash(process.stdout, "stdout")
|
|
flash(process.stderr, "stderr")
|
|
return redirect(url_for("index"))
|
|
|
|
|
|
@app.route("/files/download", methods=["POST"])
|
|
def download():
|
|
image = request.form.get("image")
|
|
return send_file(base_dir + image, as_attachment=True)
|
|
|
|
|
|
@app.route("/files/delete", methods=["POST"])
|
|
def delete():
|
|
image = request.form.get("image")
|
|
if delete_image(image):
|
|
flash("File " + image + " deleted")
|
|
return redirect(url_for("index"))
|
|
else:
|
|
flash("Failed to Delete " + image, "error")
|
|
return redirect(url_for("index"))
|
|
|
|
|
|
@app.route("/files/unzip", methods=["POST"])
|
|
def unzip():
|
|
image = request.form.get("image")
|
|
|
|
if unzip_file(image):
|
|
flash("Unzipped file " + image)
|
|
return redirect(url_for("index"))
|
|
else:
|
|
flash("Failed to unzip " + image, "error")
|
|
return redirect(url_for("index"))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
app.secret_key = "rascsi_is_awesome_insecure_secret_key"
|
|
app.config["SESSION_TYPE"] = "filesystem"
|
|
app.config["UPLOAD_FOLDER"] = base_dir
|
|
os.makedirs(app.config["UPLOAD_FOLDER"], exist_ok=True)
|
|
app.config["MAX_CONTENT_LENGTH"] = MAX_FILE_SIZE
|
|
|
|
from waitress import serve
|
|
|
|
serve(app, host="0.0.0.0", port=8080)
|