mirror of https://github.com/akuker/RASCSI.git
Web UI: Rework the Attach Device section to be universal
This commit is contained in:
parent
a52fda0fbd
commit
342ab56735
|
@ -83,11 +83,10 @@
|
|||
<td class="name" align="center">{{ device.device_name }}</td>
|
||||
<td class="parameters">
|
||||
{% if "No Media" in device.status %}
|
||||
<form action="/scsi/attach" method="post">
|
||||
<form action="/scsi/attach_device" method="post">
|
||||
<input name="scsi_id" type="hidden" value="{{ device.id }}">
|
||||
<input name="unit" type="hidden" value="{{ device.unit }}">
|
||||
<input name="type" type="hidden" value="{{ device.device_type }}">
|
||||
<input name="file_size" type="hidden" value="{{ device.size }}">
|
||||
<label for="device_list_file_name_{{ device.id }}_{{ device.unit }}">{{ _("File name") }}</label>
|
||||
<select type="select" name="file_name" id="device_list_file_name_{{ device.id }}_{{ device.unit }}">
|
||||
{% for f in files|sort(attribute='name') %}
|
||||
|
@ -187,6 +186,140 @@
|
|||
|
||||
<hr/>
|
||||
|
||||
<section id="attach-devices">
|
||||
<details>
|
||||
<summary class="heading">
|
||||
{{ _("Attach Device") }}
|
||||
</summary>
|
||||
<ul>
|
||||
</li>
|
||||
{% if bridge_configured %}
|
||||
<li>{{ _("The <tt>piscsi_bridge</tt> network bridge is active and ready to be used by an emulated network adapter!") }}</li>
|
||||
{% else %}
|
||||
<li>{{ _("Please configure the <tt>piscsi_bridge</tt> network bridge before attaching an emulated network adapter!") }}</li>
|
||||
{% endif %}
|
||||
<li>{{ _("To browse the modern web, install a vintage web proxy such as <a href=\"%(url)s\" target=\"_blank\">Macproxy</a>.", url="https://github.com/PiSCSI/piscsi/wiki/Vintage-Web-Proxy#macproxy") }}</li>
|
||||
</li>
|
||||
<li>{{ _("Read more about <a href=\"%(url)s\" target=\"_blank\">supported device types</a> on the wiki.", url="https://github.com/PiSCSI/piscsi/wiki/Supported-Device-Types") }}
|
||||
</li>
|
||||
</ul>
|
||||
</details>
|
||||
<table border="black" cellpadding="3" summary="List of peripheral devices">
|
||||
<tr>
|
||||
<th scope="col">{{ _("Device") }}</th>
|
||||
<th scope="col">{{ _("Key") }}</th>
|
||||
<th scope="col">{{ _("Parameters and Actions") }}</th>
|
||||
</tr>
|
||||
{% for type in device_types.keys() %}
|
||||
<tr>
|
||||
<td>
|
||||
<div>{{ device_types[type]["name"] }}</div>
|
||||
</td>
|
||||
<td>
|
||||
<div>{{ type }}</div>
|
||||
</td>
|
||||
<td>
|
||||
<form action="/scsi/attach_device" method="post" class="device-attach">
|
||||
<input name="type" type="hidden" value="{{ type }}">
|
||||
{% for key, value in device_types[type]["params"] | dictsort %}
|
||||
<label for="param_{{ type }}_{{ key }}">{{ key }}:</label>
|
||||
{% if value.isnumeric() %}
|
||||
<input name="param_{{ key }}" id="param_{{ type }}_{{ key }}" type="number" value="{{ value }}">
|
||||
{% elif key == "interface" %}
|
||||
<select name="param_{{ key }}" id="param_{{ type }}_{{ key }}">
|
||||
{% for if in netinfo["ifs"] %}
|
||||
<option value="{{ if }}">
|
||||
{{ if }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
{% else %}
|
||||
<input name="param_{{ key }}" id="param_{{ type }}_{{ key }}" type="text" size="{{ value|length }}" placeholder="{{ value }}">
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% if type in DISK_DEVICE_TYPES %}
|
||||
<label for="{{ type }}_drive_name">{{ _("Masquerade as:") }}</label>
|
||||
<select name="drive_name" id="{{ type }}_drive_name">
|
||||
<option value="">
|
||||
{{ _("None") }}
|
||||
</option>
|
||||
{% if type == "SCHD" %}
|
||||
{% for drive in drive_properties["hd_conf"] | sort(attribute='name') %}
|
||||
<option value="{{ drive.name }}">
|
||||
{{ drive.name }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if type == "SCCD" %}
|
||||
{% for drive in drive_properties["cd_conf"] | sort(attribute='name') %}
|
||||
<option value="{{ drive.name }}">
|
||||
{{ drive.name }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if type == "SCRM" %}
|
||||
{% for drive in drive_properties["rm_conf"] | sort(attribute='name') %}
|
||||
<option value="{{ drive.name }}">
|
||||
{{ drive.name }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if type == "SCMO" %}
|
||||
{% for drive in drive_properties["mo_conf"] | sort(attribute='name') %}
|
||||
<option value="{{ drive.name }}">
|
||||
{{ drive.name }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</select>
|
||||
<label for="{{ type }}_image_file_name">{{ _("Image file:") }}</label>
|
||||
<select name="file_name" id="{{ type }}_image_file_name">
|
||||
{% if type != "SCHD" %}
|
||||
<option value="">
|
||||
{{ _("None") }}
|
||||
</option>
|
||||
{% endif %}
|
||||
{% for f in files|sort(attribute='name') %}
|
||||
{% if type == "SCHD" %}
|
||||
{% if f["name"].lower().endswith(env['hd_suffixes']) %}
|
||||
<option value="{{ f["name"] }}">{{ f["name"].replace(env["image_dir"], '') }}</option>
|
||||
{% endif %}
|
||||
{% elif type == "SCCD" %}
|
||||
{% if f["name"].lower().endswith(env['cd_suffixes']) %}
|
||||
<option value="{{ f["name"] }}">{{ f["name"].replace(env["image_dir"], '') }}</option>
|
||||
{% endif %}
|
||||
{% elif type == "SCRM" %}
|
||||
{% if f["name"].lower().endswith(env['rm_suffixes']) %}
|
||||
<option value="{{ f["name"] }}">{{ f["name"].replace(env["image_dir"], '') }}</option>
|
||||
{% endif %}
|
||||
{% elif type == "SCMO" %}
|
||||
{% if f["name"].lower().endswith(env['mo_suffixes']) %}
|
||||
<option value="{{ f["name"] }}">{{ f["name"].replace(env["image_dir"], '') }}</option>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</select>
|
||||
{% endif %}
|
||||
<label for="{{ type }}_scsi_id">{{ _("ID") }}</label>
|
||||
<select name="scsi_id" id="{{ type }}_scsi_id">
|
||||
{% for id in scsi_ids["valid_ids"] %}
|
||||
<option value="{{ id }}"{% if id == scsi_ids["recommended_id"] %} selected{% endif %}>
|
||||
{{ id }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<label for="{{ type }}_unit">{{ _("LUN") }}</label>
|
||||
<input class="lun" name="unit" id="{{ type }}_unit" type="number" value="0" min="0" max="31" step="1" size="3">
|
||||
<input type="submit" value="{{ _("Attach") }}" title="{{ _("Attach") }}">
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<hr/>
|
||||
|
||||
<section id="files">
|
||||
<details>
|
||||
<summary class="heading">
|
||||
|
@ -218,7 +351,7 @@
|
|||
<div>
|
||||
{% for subdir, group in formatted_image_files.items() %}
|
||||
|
||||
<details class="subdir"{% if subdir == env["image_root_dir"] + "/" %} open{% endif %}>
|
||||
<details class="subdir">
|
||||
<summary class="dirname">
|
||||
{{ subdir }}
|
||||
</summary>
|
||||
|
@ -307,9 +440,8 @@
|
|||
<input type="submit" value="{{ _("Extract") }}" title="{{ _("Extract") }}" onclick="processNotify('{{ _("Extracting all files...") }}')">
|
||||
</form>
|
||||
{% else %}
|
||||
<form action="/scsi/attach" method="post" class="file-attach">
|
||||
<form action="/scsi/attach_device" method="post" class="file-attach">
|
||||
<input name="file_name" type="hidden" value="{{ file['name'] }}">
|
||||
<input name="file_size" type="hidden" value="{{ file['size'] }}">
|
||||
<label for="image_list_scsi_id_{{ file["name"] }}">{{ _("ID") }}</label>
|
||||
<select name="scsi_id" id="image_list_scsi_id_{{ file["name"] }}">
|
||||
{% for id in scsi_ids["valid_ids"] %}
|
||||
|
@ -568,105 +700,5 @@
|
|||
<a href="/drive/list"><p>{{ _("Create Disk Image With Properties") }}</p></a>
|
||||
</section>
|
||||
|
||||
<hr/>
|
||||
|
||||
<section id="attach-devices">
|
||||
<details>
|
||||
<summary class="heading">
|
||||
{{ _("Attach Peripheral Device") }}
|
||||
</summary>
|
||||
<ul>
|
||||
</li>
|
||||
{% if bridge_configured %}
|
||||
<li>{{ _("The <tt>piscsi_bridge</tt> network bridge is active and ready to be used by an emulated network adapter!") }}</li>
|
||||
{% else %}
|
||||
<li>{{ _("Please configure the <tt>piscsi_bridge</tt> network bridge before attaching an emulated network adapter!") }}</li>
|
||||
{% endif %}
|
||||
<li>{{ _("To browse the modern web, install a vintage web proxy such as <a href=\"%(url)s\" target=\"_blank\">Macproxy</a>.", url="https://github.com/PiSCSI/piscsi/wiki/Vintage-Web-Proxy#macproxy") }}</li>
|
||||
</li>
|
||||
<li>{{ _("Read more about <a href=\"%(url)s\" target=\"_blank\">supported device types</a> on the wiki.", url="https://github.com/PiSCSI/piscsi/wiki/Supported-Device-Types") }}
|
||||
</li>
|
||||
</ul>
|
||||
</details>
|
||||
<table border="black" cellpadding="3" summary="List of peripheral devices">
|
||||
<tr>
|
||||
<th scope="col">{{ _("Device") }}</th>
|
||||
<th scope="col">{{ _("Key") }}</th>
|
||||
<th scope="col">{{ _("Parameters and Actions") }}</th>
|
||||
</tr>
|
||||
{% for type in REMOVABLE_DEVICE_TYPES + PERIPHERAL_DEVICE_TYPES %}
|
||||
<tr>
|
||||
<td>
|
||||
<div>{{ device_types[type]["name"] }}</div>
|
||||
</td>
|
||||
<td>
|
||||
<div>{{ type }}</div>
|
||||
</td>
|
||||
<td>
|
||||
<form action="/scsi/attach_device" method="post" class="device-attach">
|
||||
<input name="type" type="hidden" value="{{ type }}">
|
||||
{% for key, value in device_types[type]["params"] | dictsort %}
|
||||
<label for="param_{{ type }}_{{ key }}">{{ key }}:</label>
|
||||
{% if value.isnumeric() %}
|
||||
<input name="param_{{ key }}" id="param_{{ type }}_{{ key }}" type="number" value="{{ value }}">
|
||||
{% elif key == "interface" %}
|
||||
<select name="param_{{ key }}" id="param_{{ type }}_{{ key }}">
|
||||
{% for if in netinfo["ifs"] %}
|
||||
<option value="{{ if }}">
|
||||
{{ if }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
{% else %}
|
||||
<input name="param_{{ key }}" id="param_{{ type }}_{{ key }}" type="text" size="{{ value|length }}" placeholder="{{ value }}">
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% if type in REMOVABLE_DEVICE_TYPES %}
|
||||
<label for="{{ type }}_drive_name">{{ _("Masquerade as:") }}</label>
|
||||
<select name="drive_name" id="{{ type }}_drive_name">
|
||||
<option value="">
|
||||
{{ _("None") }}
|
||||
</option>
|
||||
{% if type == "SCCD" %}
|
||||
{% for drive in drive_properties["cd_conf"] | sort(attribute='name') %}
|
||||
<option value="{{ drive.name }}">
|
||||
{{ drive.name }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if type == "SCRM" %}
|
||||
{% for drive in drive_properties["rm_conf"] | sort(attribute='name') %}
|
||||
<option value="{{ drive.name }}">
|
||||
{{ drive.name }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if type == "SCMO" %}
|
||||
{% for drive in drive_properties["mo_conf"] | sort(attribute='name') %}
|
||||
<option value="{{ drive.name }}">
|
||||
{{ drive.name }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</select>
|
||||
{% endif %}
|
||||
<label for="{{ type }}_scsi_id">{{ _("ID") }}</label>
|
||||
<select name="scsi_id" id="{{ type }}_scsi_id">
|
||||
{% for id in scsi_ids["valid_ids"] %}
|
||||
<option value="{{ id }}"{% if id == scsi_ids["recommended_id"] %} selected{% endif %}>
|
||||
{{ id }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<label for="{{ type }}_unit">{{ _("LUN") }}</label>
|
||||
<input class="lun" name="unit" id="{{ type }}_unit" type="number" value="0" min="0" max="31" step="1" size="3">
|
||||
<input type="submit" value="{{ _("Attach") }}" title="{{ _("Attach") }}">
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<hr/>
|
||||
{% endblock content %}
|
||||
|
|
|
@ -125,6 +125,7 @@ def get_env_info():
|
|||
"image_dir": server_info["image_dir"],
|
||||
"image_root_dir": Path(server_info["image_dir"]).name,
|
||||
"shared_root_dir": Path(FILE_SERVER_DIR).name,
|
||||
"hd_suffixes": tuple(server_info["schd"]),
|
||||
"cd_suffixes": tuple(server_info["sccd"]),
|
||||
"rm_suffixes": tuple(server_info["scrm"]),
|
||||
"mo_suffixes": tuple(server_info["scmo"]),
|
||||
|
@ -651,12 +652,13 @@ def log_level():
|
|||
@login_required
|
||||
def attach_device():
|
||||
"""
|
||||
Attaches a peripheral device that doesn't take an image file as argument
|
||||
Attaches device of any type
|
||||
"""
|
||||
scsi_id = request.form.get("scsi_id")
|
||||
unit = request.form.get("unit")
|
||||
device_type = request.form.get("type")
|
||||
drive_name = request.form.get("drive_name")
|
||||
file_name = request.form.get("file_name")
|
||||
|
||||
if not scsi_id:
|
||||
return response(error=True, message=_("No SCSI ID specified"))
|
||||
|
@ -690,11 +692,29 @@ def attach_device():
|
|||
"device_type": device_type,
|
||||
"params": params,
|
||||
}
|
||||
|
||||
if file_name:
|
||||
kwargs["params"]["file"] = file_name
|
||||
|
||||
# If drive_props is defined use properies from this dict,
|
||||
# otherwise fall back to the properties file if it exists
|
||||
if drive_props:
|
||||
kwargs["vendor"] = drive_props["vendor"]
|
||||
kwargs["product"] = drive_props["product"]
|
||||
kwargs["revision"] = drive_props["revision"]
|
||||
kwargs["block_size"] = drive_props["block_size"]
|
||||
else:
|
||||
drive_properties = Path(CFG_DIR) / f"{file_name}.{PROPERTIES_SUFFIX}"
|
||||
if drive_properties.is_file():
|
||||
process = file_cmd.read_drive_properties(drive_properties)
|
||||
process = ReturnCodeMapper.add_msg(process)
|
||||
if not process["status"]:
|
||||
return response(error=True, message=process["msg"])
|
||||
conf = process["conf"]
|
||||
kwargs["vendor"] = conf["vendor"]
|
||||
kwargs["product"] = conf["product"]
|
||||
kwargs["revision"] = conf["revision"]
|
||||
kwargs["block_size"] = conf["block_size"]
|
||||
|
||||
process = piscsi_cmd.attach_device(scsi_id, **kwargs)
|
||||
process = ReturnCodeMapper.add_msg(process)
|
||||
|
@ -711,70 +731,6 @@ def attach_device():
|
|||
return response(error=True, message=process["msg"])
|
||||
|
||||
|
||||
@APP.route("/scsi/attach", methods=["POST"])
|
||||
@login_required
|
||||
def attach_image():
|
||||
"""
|
||||
Attaches a file image as a device
|
||||
"""
|
||||
file_name = request.form.get("file_name")
|
||||
file_size = request.form.get("file_size")
|
||||
scsi_id = request.form.get("scsi_id")
|
||||
unit = request.form.get("unit")
|
||||
device_type = request.form.get("type")
|
||||
|
||||
if not scsi_id:
|
||||
return response(error=True, message=_("No SCSI ID specified"))
|
||||
if not file_name:
|
||||
return response(error=True, message=_("No image file to insert"))
|
||||
|
||||
kwargs = {"unit": int(unit), "params": {"file": file_name}}
|
||||
|
||||
if device_type:
|
||||
kwargs["device_type"] = device_type
|
||||
device_types = piscsi_cmd.get_device_types()
|
||||
expected_block_size = min(device_types["device_types"][device_type]["block_sizes"])
|
||||
|
||||
# Attempt to load the device properties file:
|
||||
# same file name with PROPERTIES_SUFFIX appended
|
||||
drive_properties = Path(CFG_DIR) / f"{file_name}.{PROPERTIES_SUFFIX}"
|
||||
if drive_properties.is_file():
|
||||
process = file_cmd.read_drive_properties(drive_properties)
|
||||
process = ReturnCodeMapper.add_msg(process)
|
||||
if not process["status"]:
|
||||
return response(error=True, message=process["msg"])
|
||||
conf = process["conf"]
|
||||
kwargs["vendor"] = conf["vendor"]
|
||||
kwargs["product"] = conf["product"]
|
||||
kwargs["revision"] = conf["revision"]
|
||||
kwargs["block_size"] = conf["block_size"]
|
||||
expected_block_size = conf["block_size"]
|
||||
|
||||
process = piscsi_cmd.attach_device(scsi_id, **kwargs)
|
||||
process = ReturnCodeMapper.add_msg(process)
|
||||
if process["status"]:
|
||||
if int(file_size) % int(expected_block_size):
|
||||
logging.warning(
|
||||
"The image file size %s bytes is not a multiple of %s. "
|
||||
"PiSCSI will ignore the trailing data. "
|
||||
"The image may be corrupted, so proceed with caution.",
|
||||
file_size,
|
||||
expected_block_size,
|
||||
)
|
||||
return response(
|
||||
message=_(
|
||||
"Attached %(file_name)s as %(device_type)s to "
|
||||
"SCSI ID %(id_number)s LUN %(unit_number)s",
|
||||
file_name=file_name,
|
||||
device_type=get_device_name(device_type),
|
||||
id_number=scsi_id,
|
||||
unit_number=unit,
|
||||
)
|
||||
)
|
||||
|
||||
return response(error=True, message=process["msg"])
|
||||
|
||||
|
||||
@APP.route("/scsi/detach_all", methods=["POST"])
|
||||
@login_required
|
||||
def detach_all_devices():
|
||||
|
|
|
@ -2,20 +2,18 @@ import pytest
|
|||
|
||||
from conftest import (
|
||||
SCSI_ID,
|
||||
FILE_SIZE_1_MIB,
|
||||
STATUS_SUCCESS,
|
||||
)
|
||||
|
||||
|
||||
# route("/scsi/attach", methods=["POST"])
|
||||
def test_attach_image(http_client, create_test_image, detach_devices):
|
||||
# route("/scsi/attach_device", methods=["POST"])
|
||||
def test_attach_device_with_image(http_client, create_test_image, detach_devices):
|
||||
test_image = create_test_image()
|
||||
|
||||
response = http_client.post(
|
||||
"/scsi/attach",
|
||||
"/scsi/attach_device",
|
||||
data={
|
||||
"file_name": test_image,
|
||||
"file_size": FILE_SIZE_1_MIB,
|
||||
"scsi_id": SCSI_ID,
|
||||
"unit": 0,
|
||||
"type": "SCHD",
|
||||
|
@ -26,7 +24,7 @@ def test_attach_image(http_client, create_test_image, detach_devices):
|
|||
assert response.status_code == 200
|
||||
assert response_data["status"] == STATUS_SUCCESS
|
||||
assert response_data["messages"][0]["message"] == (
|
||||
f"Attached {test_image} as Hard Disk Drive to SCSI ID {SCSI_ID} LUN 0"
|
||||
f"Attached Hard Disk Drive to SCSI ID {SCSI_ID} LUN 0"
|
||||
)
|
||||
|
||||
# Cleanup
|
||||
|
@ -110,10 +108,9 @@ def test_detach_device(http_client, create_test_image):
|
|||
test_image = create_test_image()
|
||||
|
||||
http_client.post(
|
||||
"/scsi/attach",
|
||||
"/scsi/attach_device",
|
||||
data={
|
||||
"file_name": test_image,
|
||||
"file_size": FILE_SIZE_1_MIB,
|
||||
"scsi_id": SCSI_ID,
|
||||
"unit": 0,
|
||||
"type": "SCHD",
|
||||
|
@ -145,10 +142,9 @@ def test_detach_all_devices(http_client, create_test_image, list_attached_images
|
|||
test_images.append(test_image)
|
||||
|
||||
http_client.post(
|
||||
"/scsi/attach",
|
||||
"/scsi/attach_device",
|
||||
data={
|
||||
"file_name": test_image,
|
||||
"file_size": FILE_SIZE_1_MIB,
|
||||
"scsi_id": scsi_id,
|
||||
"unit": 0,
|
||||
"type": "SCHD",
|
||||
|
@ -170,10 +166,9 @@ def test_eject_device(http_client, create_test_image, detach_devices):
|
|||
test_image = create_test_image()
|
||||
|
||||
http_client.post(
|
||||
"/scsi/attach",
|
||||
"/scsi/attach_device",
|
||||
data={
|
||||
"file_name": test_image,
|
||||
"file_size": FILE_SIZE_1_MIB,
|
||||
"scsi_id": SCSI_ID,
|
||||
"unit": 0,
|
||||
"type": "SCCD", # CD-ROM
|
||||
|
@ -203,10 +198,9 @@ def test_show_device_info(http_client, create_test_image, detach_devices):
|
|||
test_image = create_test_image()
|
||||
|
||||
http_client.post(
|
||||
"/scsi/attach",
|
||||
"/scsi/attach_device",
|
||||
data={
|
||||
"file_name": test_image,
|
||||
"file_size": FILE_SIZE_1_MIB,
|
||||
"scsi_id": SCSI_ID,
|
||||
"unit": 0,
|
||||
"type": "SCHD",
|
||||
|
|
Loading…
Reference in New Issue