mirror of
https://github.com/akuker/RASCSI.git
synced 2024-11-25 20:33:35 +00:00
Add DaynaPORT config to web
Add bridge-utils Minor fixes to easyinstall Can now save config, detach all devices Bridge script error out if any command fails
This commit is contained in:
parent
943a9ab537
commit
0b78f09f8d
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,3 +1,6 @@
|
||||
venv
|
||||
*.pyc
|
||||
core
|
||||
.idea/
|
||||
.DS_Store
|
||||
*.swp
|
||||
|
@ -28,7 +28,7 @@ LIDO_DRIVER=~/RASCSI/lido-driver.img
|
||||
|
||||
function initialChecks() {
|
||||
currentUser=$(whoami)
|
||||
if [ "pi" != $currentUser ]; then
|
||||
if [ "pi" != "$currentUser" ]; then
|
||||
echo "You must use 'pi' user (current: $currentUser)"
|
||||
exit 1
|
||||
fi
|
||||
@ -40,10 +40,14 @@ function initialChecks() {
|
||||
fi
|
||||
}
|
||||
|
||||
function installPackages() {
|
||||
sudo apt-get update && sudo apt install git libspdlog-dev genisoimage python3 python3-venv nginx bridge-utils -y
|
||||
}
|
||||
|
||||
# install all dependency packages for RaSCSI Service
|
||||
# compile and install RaSCSI Service
|
||||
function installRaScsi() {
|
||||
installPackages
|
||||
sudo apt-get update && sudo apt-get install --yes git libspdlog-dev
|
||||
|
||||
cd ~/RASCSI/src/raspberrypi
|
||||
@ -69,7 +73,7 @@ www-data ALL=NOPASSWD: /sbin/shutdown, /sbin/reboot
|
||||
|
||||
function stopOldWebInterface() {
|
||||
APACHE_STATUS=$(sudo systemctl status apache2 &> /dev/null; echo $?)
|
||||
if [ $APACHE_STATUS -eq 0 ] ; then
|
||||
if [ "$APACHE_STATUS" -eq 0 ] ; then
|
||||
echo "Stopping old Apache2 RaSCSI Web..."
|
||||
sudo systemctl disable apache2
|
||||
sudo systemctl stop apache2
|
||||
@ -79,7 +83,7 @@ function stopOldWebInterface() {
|
||||
# install everything required to run an HTTP server (Nginx + Python Flask App)
|
||||
function installRaScsiWebInterface() {
|
||||
stopOldWebInterface
|
||||
sudo apt install genisoimage python3 python3-venv nginx -y
|
||||
installPackages
|
||||
|
||||
sudo cp -f ~/RASCSI/src/web/service-infra/nginx-default.conf /etc/nginx/sites-available/default
|
||||
sudo cp -f ~/RASCSI/src/web/service-infra/502.html /var/www/html/502.html
|
||||
@ -100,11 +104,15 @@ function installRaScsiWebInterface() {
|
||||
|
||||
function updateRaScsiGit() {
|
||||
cd ~/RASCSI
|
||||
git pull
|
||||
git fetch
|
||||
git stash
|
||||
git rebase origin/master
|
||||
git stash apply
|
||||
}
|
||||
|
||||
function updateRaScsi() {
|
||||
updateRaScsiGit
|
||||
installPackages
|
||||
sudo systemctl stop rascsi
|
||||
|
||||
cd ~/RASCSI/src/raspberrypi
|
||||
@ -241,8 +249,8 @@ function showMenu() {
|
||||
choice=-1
|
||||
|
||||
until [ $choice -ge "0" ] && [ $choice -le "7" ]; do
|
||||
echo "Enter your choice (0-7) or CTRL-C to exit"
|
||||
read choice
|
||||
echo -n "Enter your choice (0-7) or CTRL-C to exit: "
|
||||
read -r choice
|
||||
done
|
||||
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
#!/bin/bash
|
||||
set -e # Fail if any command fails
|
||||
sudo brctl addbr rascsi_bridge
|
||||
sudo brctl addif rascsi_bridge eth0
|
||||
sudo ip link set dev rascsi_bridge up
|
||||
|
@ -64,7 +64,7 @@ def download_file_to_iso(scsi_id, url):
|
||||
)
|
||||
if iso_proc.returncode != 0:
|
||||
return iso_proc
|
||||
return attach_image(scsi_id, iso_filename, "cd")
|
||||
return attach_image(scsi_id, iso_filename, "SCCD")
|
||||
|
||||
|
||||
def download_image(url):
|
||||
|
12
src/web/mock/bin/brctl
Normal file
12
src/web/mock/bin/brctl
Normal file
@ -0,0 +1,12 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Mock responses to rascsi-web
|
||||
case $1 in
|
||||
"show")
|
||||
echo "rascsi_bridge 8000.dca632b05dd1 no eth0"
|
||||
;;
|
||||
|
||||
**)
|
||||
echo "default"
|
||||
;;
|
||||
esac
|
12
src/web/mock/bin/ip
Normal file
12
src/web/mock/bin/ip
Normal file
@ -0,0 +1,12 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Mock responses to rascsi-web
|
||||
case $1 in
|
||||
"link")
|
||||
echo "link here"
|
||||
;;
|
||||
|
||||
**)
|
||||
echo "default"
|
||||
;;
|
||||
esac
|
@ -37,6 +37,15 @@ def list_files():
|
||||
return files_list
|
||||
|
||||
|
||||
def list_config_files():
|
||||
files_list = []
|
||||
for root, dirs, files in os.walk(base_dir):
|
||||
for file in files:
|
||||
if file.endswith(".csv"):
|
||||
files_list.append(file)
|
||||
return files_list
|
||||
|
||||
|
||||
def get_valid_scsi_ids(devices):
|
||||
invalid_list = EXCLUDE_SCSI_IDS.copy()
|
||||
for device in devices:
|
||||
@ -55,12 +64,16 @@ def get_type(scsi_id):
|
||||
return list_devices()[int(scsi_id)]["type"]
|
||||
|
||||
|
||||
def attach_image(scsi_id, image, type):
|
||||
if type == "cd" and get_type(scsi_id) == "SCCD":
|
||||
def attach_image(scsi_id, image, device_type):
|
||||
if device_type == "SCCD" and get_type(scsi_id) == "SCCD":
|
||||
return insert(scsi_id, image)
|
||||
elif device_type == "SCDP":
|
||||
attach_daynaport(scsi_id)
|
||||
else:
|
||||
if device_type == "SCCD":
|
||||
device_type = "cd"
|
||||
return subprocess.run(
|
||||
["rasctl", "-c", "attach", "-t", type, "-i", scsi_id, "-f", image],
|
||||
["rasctl", "-c", "attach", "-t", device_type, "-i", scsi_id, "-f", image],
|
||||
capture_output=True,
|
||||
)
|
||||
|
||||
@ -69,6 +82,11 @@ def detach_by_id(scsi_id):
|
||||
return subprocess.run(["rasctl", "-c" "detach", "-i", scsi_id], capture_output=True)
|
||||
|
||||
|
||||
def detach_all():
|
||||
for scsi_id in range(0, 7):
|
||||
subprocess.run(["rasctl", "-c" "detach", "-i", str(scsi_id)])
|
||||
|
||||
|
||||
def disconnect_by_id(scsi_id):
|
||||
return subprocess.run(
|
||||
["rasctl", "-c", "disconnect", "-i", scsi_id], capture_output=True
|
||||
@ -85,6 +103,28 @@ def insert(scsi_id, image):
|
||||
)
|
||||
|
||||
|
||||
def attach_daynaport(scsi_id):
|
||||
return subprocess.run(
|
||||
["rasctl", "-i", scsi_id, "-c", "attach", "-t", "daynaport"],
|
||||
capture_output=True,
|
||||
)
|
||||
|
||||
|
||||
def is_bridge_setup(interface):
|
||||
process = subprocess.run(["brctl", "show"], capture_output=True)
|
||||
output = process.stdout.decode("utf-8")
|
||||
if "rascsi_bridge" in output and interface in output:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def daynaport_setup_bridge(interface):
|
||||
return subprocess.run(
|
||||
[f"{base_dir}../RASCSI/src/raspberrypi/setup_bridge.sh", interface],
|
||||
capture_output=True,
|
||||
)
|
||||
|
||||
|
||||
def rascsi_service(action):
|
||||
# start/stop/restart
|
||||
return (
|
||||
|
@ -21,6 +21,22 @@
|
||||
|
||||
{% block content %}
|
||||
<h2>Current RaSCSI Configuration</h2>
|
||||
<form action="/config/load" method="post">
|
||||
<select name="name" >
|
||||
{% for config in config_files %}
|
||||
<option value="{{config}}">{{config.replace(".csv", '')}}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<input type="submit" value="Load" />
|
||||
</form>
|
||||
<form action="/config/save" method="post">
|
||||
<input name="name" placeholder="default">
|
||||
<input type="submit" value="Save" />
|
||||
</form>
|
||||
<form action="/scsi/detach_all" method="post" onsubmit="return confirm('Detach all SCSI Devices?')">
|
||||
<input type="submit" value="Detach All" />
|
||||
</form>
|
||||
|
||||
<table cellpadding="3" border="black">
|
||||
<tbody>
|
||||
<tr>
|
||||
@ -103,7 +119,35 @@
|
||||
</table>
|
||||
|
||||
<hr/>
|
||||
<h2>Attach Ethernet Adapter</h2>
|
||||
<p>Emulates a SCSI DaynaPORT Ethernet Adapter. Host drivers required.</p>
|
||||
<table style="border: none">
|
||||
<tr style="border: none">
|
||||
<td style="border: none; vertical-align:top;">
|
||||
<form action="/daynaport/attach" method="post">
|
||||
<select name="scsi_id">
|
||||
{% for id in scsi_ids %}
|
||||
<option value="{{id}}">{{id}}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<input type="submit" value="Attach" />
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="border: none">
|
||||
<td style="border: none; vertical-align:top;">
|
||||
{% if bridge_configured %}
|
||||
<small>Bridge is currently configured!</small>
|
||||
{% else %}
|
||||
<form action="/daynaport/setup" method="post">
|
||||
<input type="submit" value="Create Bridge" />
|
||||
</form>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<hr/>
|
||||
<h2>Upload File</h2>
|
||||
<p>Uploads file to <tt>{{base_dir}}</tt>. Max file size is set to {{max_file_size / 1024 /1024 }}MB</p>
|
||||
<table style="border: none">
|
||||
@ -183,7 +227,6 @@
|
||||
</table>
|
||||
|
||||
<hr/>
|
||||
|
||||
<h2>Raspberry Pi Operations</h2>
|
||||
<table style="border: none">
|
||||
<tr style="border: none">
|
||||
|
100
src/web/web.py
100
src/web/web.py
@ -1,5 +1,3 @@
|
||||
import os
|
||||
|
||||
from flask import Flask, render_template, request, flash, url_for, redirect, send_file
|
||||
from werkzeug.utils import secure_filename
|
||||
|
||||
@ -19,6 +17,11 @@ from ractl_cmds import (
|
||||
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 *
|
||||
|
||||
@ -31,9 +34,11 @@ def index():
|
||||
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,
|
||||
@ -41,6 +46,37 @@ def index():
|
||||
)
|
||||
|
||||
|
||||
@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
|
||||
@ -52,7 +88,36 @@ def logs():
|
||||
headers = {"content-type": "text/plain"}
|
||||
return process.stdout.decode("utf-8"), 200, headers
|
||||
else:
|
||||
flash(u"Failed to get logs")
|
||||
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"))
|
||||
@ -69,31 +134,36 @@ def attach():
|
||||
elif file_name.lower().endswith(".hda"):
|
||||
image_type = "hd"
|
||||
else:
|
||||
flash(u"Unknown file type. Valid files are .iso, .hda, .cdr", "error")
|
||||
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("Attached " + file_name + " to scsi id " + scsi_id + "!")
|
||||
flash(f"Attached {file_name} to SCSI id {scsi_id}!")
|
||||
return redirect(url_for("index"))
|
||||
else:
|
||||
flash(
|
||||
u"Failed to attach " + file_name + " to scsi id " + scsi_id + "!", "error"
|
||||
)
|
||||
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 + "!")
|
||||
flash("Detached SCSI id " + scsi_id + "!")
|
||||
return redirect(url_for("index"))
|
||||
else:
|
||||
flash(u"Failed to detach scsi id " + scsi_id + "!", "error")
|
||||
flash("Failed to detach SCSI id " + scsi_id + "!", "error")
|
||||
flash(process.stdout, "stdout")
|
||||
flash(process.stderr, "stderr")
|
||||
return redirect(url_for("index"))
|
||||
@ -107,7 +177,7 @@ def eject():
|
||||
flash("Ejected scsi id " + scsi_id + "!")
|
||||
return redirect(url_for("index"))
|
||||
else:
|
||||
flash(u"Failed to eject scsi id " + scsi_id + "!", "error")
|
||||
flash("Failed to eject SCSI id " + scsi_id + "!", "error")
|
||||
flash(process.stdout, "stdout")
|
||||
flash(process.stderr, "stderr")
|
||||
return redirect(url_for("index"))
|
||||
@ -143,7 +213,7 @@ def download_file():
|
||||
flash("File Downloaded")
|
||||
return redirect(url_for("index"))
|
||||
else:
|
||||
flash(u"Failed to download file", "error")
|
||||
flash("Failed to download file", "error")
|
||||
flash(process.stdout, "stdout")
|
||||
flash(process.stderr, "stderr")
|
||||
return redirect(url_for("index"))
|
||||
@ -181,7 +251,7 @@ def create_file():
|
||||
flash("Drive created")
|
||||
return redirect(url_for("index"))
|
||||
else:
|
||||
flash(u"Failed to create file", "error")
|
||||
flash("Failed to create file", "error")
|
||||
flash(process.stdout, "stdout")
|
||||
flash(process.stderr, "stderr")
|
||||
return redirect(url_for("index"))
|
||||
@ -200,7 +270,7 @@ def delete():
|
||||
flash("File " + image + " deleted")
|
||||
return redirect(url_for("index"))
|
||||
else:
|
||||
flash(u"Failed to Delete " + image, "error")
|
||||
flash("Failed to Delete " + image, "error")
|
||||
return redirect(url_for("index"))
|
||||
|
||||
|
||||
@ -212,7 +282,7 @@ def unzip():
|
||||
flash("Unzipped file " + image)
|
||||
return redirect(url_for("index"))
|
||||
else:
|
||||
flash(u"Failed to unzip " + image, "error")
|
||||
flash("Failed to unzip " + image, "error")
|
||||
return redirect(url_for("index"))
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user