Add docstrings and clean up layout

This commit is contained in:
Daniel Markstedt 2021-09-29 07:03:10 -07:00
parent ff00b6005c
commit 44298bf031

View File

@ -5,6 +5,15 @@ import rascsi_interface_pb2 as proto
def get_server_info():
"""
Sends a SERVER_INFO command to the server.
Returns a dict with:
- boolean status
- str version (RaSCSI version number)
- list of str log_levels (the log levels RaSCSI supports)
- str current_log_level
- list of int reserved_ids
"""
command = proto.PbCommand()
command.operation = proto.PbOperation.SERVER_INFO
@ -17,10 +26,22 @@ def get_server_info():
log_levels = result.server_info.log_levels
current_log_level = result.server_info.current_log_level
reserved_ids = list(result.server_info.reserved_ids)
return {"status": result.status, "version": version, "log_levels": log_levels, "current_log_level": current_log_level, "reserved_ids": reserved_ids}
return {
"status": result.status,
"version": version,
"log_levels": log_levels,
"current_log_level": current_log_level,
"reserved_ids": reserved_ids
}
def get_network_info():
"""
Sends a NETWORK_INTERFACES_INFO command to the server.
Returns a dict with:
- boolean status
- list of str ifs (network interfaces detected by RaSCSI)
"""
command = proto.PbCommand()
command.operation = proto.PbOperation.NETWORK_INTERFACES_INFO
@ -32,6 +53,12 @@ def get_network_info():
def get_device_types():
"""
Sends a DEVICE_TYPES_INFO command to the server.
Returns a dict with:
- boolean status
- list of str device_types (device types that RaSCSI supports, ex. SCHD, SCCD, etc)
"""
command = proto.PbCommand()
command.operation = proto.PbOperation.DEVICE_TYPES_INFO
@ -45,6 +72,12 @@ def get_device_types():
def validate_scsi_id(scsi_id):
"""
Checks that scsi_id is a valid SCSI ID, i.e. a number between 0 and 7.
Returns a dict with:
- boolean status
- str msg (result message)
"""
from re import match
if match("[0-7]", str(scsi_id)) != None:
return {"status": True, "msg": "Valid SCSI ID."}
@ -53,6 +86,10 @@ def validate_scsi_id(scsi_id):
def get_valid_scsi_ids(devices, reserved_ids):
"""
Takes a list of dicts devices, and list of ints reserved_ids.
Returns a list of ints valid_ids, which are the SCSI ids where it is possible to attach a device.
"""
occupied_ids = []
for d in devices:
# Make it possible to insert images on top of a
@ -69,12 +106,23 @@ def get_valid_scsi_ids(devices, reserved_ids):
except:
# May reach this state if the RaSCSI Web UI thinks an ID
# is reserved but RaSCSI has not actually reserved it.
logging.warning(f"SCSI ID {id} flagged as both valid and invalid. Try restarting the RaSCSI Web UI.")
logging.warning(f"SCSI ID {id} flagged as both valid and invalid. \
Try restarting the RaSCSI Web UI.")
valid_ids.reverse()
return valid_ids
def attach_image(scsi_id, **kwargs):
"""
Takes int scsi_id and kwargs containing 0 or more device properties
If the current attached device is a removable device wihout media inserted,
this sends a INJECT command to the server.
If there is no currently attached device, this sends the ATTACH command to the server.
Returns boolean status and return message str msg
"""
command = proto.PbCommand()
devices = proto.PbDeviceDefinition()
devices.id = int(scsi_id)
@ -130,6 +178,10 @@ def attach_image(scsi_id, **kwargs):
def detach_by_id(scsi_id):
"""
Takes int scsi_id and sends a DETACH command to the server.
Returns boolean status and return message str msg.
"""
devices = proto.PbDeviceDefinition()
devices.id = int(scsi_id)
@ -144,6 +196,10 @@ def detach_by_id(scsi_id):
def detach_all():
"""
Sends a DETACH_ALL command to the server.
Returns boolean status and return message str msg.
"""
command = proto.PbCommand()
command.operation = proto.PbOperation.DETACH_ALL
@ -154,6 +210,10 @@ def detach_all():
def eject_by_id(scsi_id):
"""
Takes int scsi_id and sends an EJECT command to the server.
Returns boolean status and return message str msg.
"""
devices = proto.PbDeviceDefinition()
devices.id = int(scsi_id)
@ -168,6 +228,13 @@ def eject_by_id(scsi_id):
def list_devices(scsi_id=None):
"""
Takes optional int scsi_id and sends a DEVICES_INFO command to the server.
If no scsi_id is provided, returns a list of dicts of all attached devices.
If scsi_id is is provided, returns a list of one dict for the given device.
If no attached device is found, returns an empty list.
Returns bolean status, list of dicts device_list
"""
from os import path
command = proto.PbCommand()
command.operation = proto.PbOperation.DEVICES_INFO
@ -226,6 +293,11 @@ def list_devices(scsi_id=None):
def sort_and_format_devices(devices):
"""
Takes a list of dicts devices and returns a list of dicts.
Sorts by SCSI ID acending (0 to 7).
For SCSI IDs where no device is attached, inject a dict with placeholder text.
"""
occupied_ids = []
for d in devices:
occupied_ids.append(d["id"])
@ -244,7 +316,11 @@ def sort_and_format_devices(devices):
def set_log_level(log_level):
'''Sends a command to the server to change the log level. Takes target log level as an argument.'''
"""
Sends a LOG_LEVEL command to the server.
Takes str log_level as an argument.
Returns bolean status and str msg.
"""
command = proto.PbCommand()
command.operation = proto.PbOperation.LOG_LEVEL
command.params["level"] = str(log_level)
@ -256,6 +332,10 @@ def set_log_level(log_level):
def send_pb_command(payload):
"""
Takes a str containing a serialized protobuf as argument.
Establishes a socket connection with RaSCSI.
"""
# Host and port number where rascsi is listening for socket connections
HOST = 'localhost'
PORT = 6868
@ -285,6 +365,13 @@ def send_pb_command(payload):
def send_over_socket(s, payload):
"""
Takes a socket object and str payload with serialized protobuf.
Sends payload to RaSCSI over socket and captures the response.
Tries to extract and interpret the protobuf header to get response size.
Reads data from socket in 2048 bytes chunks until all data is received.
"""
from struct import pack, unpack
# Prepending a little endian 32bit header with the message size
@ -303,13 +390,20 @@ def send_over_socket(s, payload):
chunk = s.recv(min(response_length - bytes_recvd, 2048))
if chunk == b'':
from flask import abort
logging.error("Read an empty chunk from the socket. Socket connection may have dropped unexpectedly. Check if RaSCSI has crashed.")
abort(503, "Lost connection to RaSCSI. Please go back and try again. If the issue persists, please report a bug.")
logging.error("Read an empty chunk from the socket. \
Socket connection has dropped unexpectedly. \
RaSCSI may have has crashed.")
abort(503, "Lost connection to RaSCSI. \
Please go back and try again. \
If the issue persists, please report a bug.")
chunks.append(chunk)
bytes_recvd = bytes_recvd + len(chunk)
response_message = b''.join(chunks)
return response_message
else:
from flask import abort
logging.error("The response from RaSCSI did not contain a protobuf header.")
abort(500, "Did not get a valid response from RaSCSI. Please go back and try again. If the issue persists, please report a bug.")
logging.error("The response from RaSCSI did not contain a protobuf header. \
RaSCSI may have crashed.")
abort(500, "Did not get a valid response from RaSCSI. \
Please go back and try again. \
If the issue persists, please report a bug.")