diff options
Diffstat (limited to 'src/dashboard')
-rw-r--r-- | src/dashboard/admin_utils.py | 217 |
1 files changed, 168 insertions, 49 deletions
diff --git a/src/dashboard/admin_utils.py b/src/dashboard/admin_utils.py index 76db762..d97b6ed 100644 --- a/src/dashboard/admin_utils.py +++ b/src/dashboard/admin_utils.py @@ -42,12 +42,37 @@ from api.models import JobStatus def print_div(): - print("====================================================================") + """ + Utility function for printing dividers, does nothing directly useful as a utility + """ + print("=" * 68) def book_host(owner_username, host_labid, lab_username, hostname, image_id, template_name, length_days=21, collaborator_usernames=[], purpose="internal", project="LaaS"): """ creates a quick booking using the given host + + @owner_username is the simple username for the user who will own the resulting booking. + Do not set this to a lab username! + + @image_id is the django id of the image in question, NOT the labid of the image. + Query Image objects by their public status and compatible host types + + @host_labid is usually of the form `hpe3` or similar, is the labid of the Server (subtype of Resource) object + + @lab_username for iol is `unh_iol`, other labs will be documented here + + @hostname the hostname that the resulting host should have set + + @template_name the name of the (public, or user accessible) template to use for this booking + + @length_days how long the booking should be, no hard limit currently + + @collaborator_usernames a list of usernames for collaborators to the booking + + @purpose what this booking will be used for + + @project what project/group this booking is on behalf of or the owner represents """ lab = Lab.objects.get(lab_user__username=lab_username) host = Server.objects.filter(lab=lab).get(labid=host_labid) @@ -116,6 +141,16 @@ def book_host(owner_username, host_labid, lab_username, hostname, image_id, temp def mark_working(host_labid, lab_username, working=True): + """ + Mark a host working/not working so that it is either bookable or hidden in the dashboard. + + @host_labid is usually of the form `hpe3` or similar, is the labid of the Server (subtype of Resource) object + + @lab_username: param of the form `unh_iol` or similar + + @working: bool, whether by the end of execution the host should be considered working or not working + """ + lab = Lab.objects.get(lab_user__username=lab_username) server = Server.objects.filter(lab=lab).get(labid=host_labid) print("changing server working status from ", server.working, "to", working) @@ -124,6 +159,16 @@ def mark_working(host_labid, lab_username, working=True): def mark_booked(host_labid, lab_username, booked=True): + """ + Mark a host as booked/unbooked + + @host_labid is usually of the form `hpe3` or similar, is the labid of the Server (subtype of Resource) object + + @lab_username: param of the form `unh_iol` or similar + + @working: bool, whether by the end of execution the host should be considered booked or not booked + """ + lab = Lab.objects.get(lab_user__username=lab_username) server = Server.objects.filter(lab=lab).get(labid=host_labid) print("changing server booked status from ", server.booked, "to", booked) @@ -131,13 +176,26 @@ def mark_booked(host_labid, lab_username, booked=True): server.save() -# returns host filtered by lab and then unique id within lab def get_host(host_labid, lab_username): + """ + Returns host filtered by lab and then unique id within lab + + @host_labid is usually of the form `hpe3` or similar, is the labid of the Server (subtype of Resource) object + + @lab_username: param of the form `unh_iol` or similar + """ lab = Lab.objects.get(lab_user__username=lab_username) return Server.objects.filter(lab=lab).get(labid=host_labid) def get_info(host_labid, lab_username): + """ + Returns various information on the host queried by the given parameters + + @host_labid is usually of the form `hpe3` or similar, is the labid of the Server (subtype of Resource) object + + @lab_username: param of the form `unh_iol` or similar + """ info = {} host = get_host(host_labid, lab_username) info['host_labid'] = host_labid @@ -202,8 +260,16 @@ def detect_leaked_hosts(labid="unh_iol"): return filtered -def booking_for_host(host_labid: str, labid="unh_iol"): - server = Server.objects.get(lab__lab_user__username=labid, labid=host_labid) +def booking_for_host(host_labid: str, lab_username="unh_iol"): + """ + Returns the booking that this server is a part of, if any. + Fails with an exception if no such booking exists + + @host_labid is usually of the form `hpe3` or similar, is the labid of the Server (subtype of Resource) object + + @lab_username: param of the form `unh_iol` or similar + """ + server = Server.objects.get(lab__lab_user__username=lab_username, lab_username=host_labid) booking = server.bundle.booking_set.first() print_div() print(booking) @@ -214,7 +280,15 @@ def booking_for_host(host_labid: str, labid="unh_iol"): return booking -def force_release_booking(booking_id): +def force_release_booking(booking_id: int): + """ + Takes a booking id and forces the booking to end whether or not the tasks have + completed normally. + + Use with caution! Hosts may or may not be released depending on other underlying issues + + @booking_id: the id of the Booking object to be released + """ booking = Booking.objects.get(id=booking_id) job = booking.job tasks = job.get_tasklist() @@ -224,6 +298,12 @@ def force_release_booking(booking_id): def get_network_metadata(booking_id: int): + """ + Takes a booking id and prints all (known) networks that are owned by it. + Returns an object of the form {<network name>: {"vlan_id": int, "netname": str <network name>, "public": bool <whether network is public/routable}} + + @booking_id: the id of the Booking object to be queried + """ booking = Booking.objects.get(id=booking_id) bundle = booking.resource pnets = PhysicalNetwork.objects.filter(bundle=bundle).all() @@ -236,46 +316,50 @@ def get_network_metadata(booking_id: int): def print_dict_pretty(a_dict): + """ + admin_utils internal function + """ + print(json.dumps(a_dict, sort_keys=True, indent=4)) -""" -schema: -{ - "name": str - "description": str - "labs": [ - str (lab username) - ] - "disks": { - <diskname> : { - capacity: int (GiB) - media_type: str ("SSD" or "HDD") - interface: str ("sata", "sas", "ssd", "nvme", "scsi", or "iscsi") +def add_profile(data): + """ + Used for adding a host profile to the dashboard + + schema (of dict passed as "data" param): + { + "name": str + "description": str + "labs": [ + str (lab username) + ] + "disks": { + <diskname> : { + capacity: int (GiB) + media_type: str ("SSD" or "HDD") + interface: str ("sata", "sas", "ssd", "nvme", "scsi", or "iscsi") + } } - } - interfaces: { - <intname>: { - "speed": int (mbit) - "nic_type": str ("onboard" or "pcie") - "order": int (compared to the other interfaces, indicates the "order" that the ports are laid out) + interfaces: { + <intname>: { + "speed": int (mbit) + "nic_type": str ("onboard" or "pcie") + "order": int (compared to the other interfaces, indicates the "order" that the ports are laid out) + } + } + cpus: { + cores: int (hardware threads count) + architecture: str (x86_64" or "aarch64") + cpus: int (number of sockets) + cflags: str + } + ram: { + amount: int (GiB) + channels: int } } - cpus: { - cores: int (hardware threads count) - architecture: str (x86_64" or "aarch64") - cpus: int (number of sockets) - cflags: str - } - ram: { - amount: int (GiB) - channels: int - } -} -""" - - -def add_profile(data): + """ base_profile = ResourceProfile.objects.create(name=data['name'], description=data['description']) base_profile.save() @@ -306,6 +390,11 @@ def add_profile(data): def make_default_template(resource_profile, image_id=None, template_name=None, connected_interface_names=None, interfaces_tagged=False, connected_interface_tagged=False, owner_username="root", lab_username="unh_iol", public=True, temporary=False, description=""): + """ + Do not call this function without reading the related source code, it may have unintended effects. + + Used for creating a default template from some host profile + """ if not resource_profile: raise Exception("No viable continuation from none resource_profile") @@ -352,16 +441,27 @@ def make_default_template(resource_profile, image_id=None, template_name=None, c connection.save() -""" -Note: interfaces should be dict from interface name (eg ens1f0) to dict of schema: - { - mac_address: <mac addr>, - bus_addr: <bus addr>, //this field is optional, "" is default - } -""" +def add_server(profile, name, interfaces, lab_username="unh_iol", vendor="unknown", model="unknown"): + """ + Used to enroll a new host of some profile + + @profile: the ResourceProfile in question (by reference to a model object) + + @name: the unique name of the server, currently indistinct from labid + + @interfaces: interfaces should be dict from interface name (eg ens1f0) to dict of schema: + { + mac_address: <mac addr>, + bus_addr: <bus addr>, //this field is optional, "" is default + } + + @lab_username: username of the lab to be added to + + @vendor: vendor name of the host, such as "HPE" or "Gigabyte" + @model: specific model of the host, such as "DL380 Gen 9" -def add_server(profile, uname, interfaces, lab_username="unh_iol", vendor="unknown", model="unknown"): + """ server = Server.objects.create( bundle=None, profile=profile, @@ -369,9 +469,9 @@ def add_server(profile, uname, interfaces, lab_username="unh_iol", vendor="unkno working=True, vendor=vendor, model=model, - labid=uname, + labid=name, lab=Lab.objects.get(lab_user__username=lab_username), - name=uname, + name=name, booked=False) for iface_prof in InterfaceProfile.objects.filter(host=profile).all(): @@ -388,12 +488,25 @@ def add_server(profile, uname, interfaces, lab_username="unh_iol", vendor="unkno def extend_booking(booking_id, days=0, hours=0, minutes=0, weeks=0): + """ + Extend a booking by n <days, hours, minutes, weeks> + + @booking_id: id of the booking + + @days/@hours/@minutes/@weeks: the cumulative amount of delta to add to the length of the booking + """ + booking = Booking.objects.get(id=booking_id) booking.end = booking.end + timedelta(days=days, hours=hours, minutes=minutes, weeks=weeks) booking.save() def docs(function=None, fulltext=False): + """ + Print documentation for a given function in admin_utils. + Call without arguments for more information + """ + fn = None if isinstance(function, str): @@ -422,7 +535,13 @@ def docs(function=None, fulltext=False): def admin_functions(): + """ + List functions available to call within admin_utils + """ + return [name for name, func in inspect.getmembers(sys.modules[__name__]) if (inspect.isfunction(func) and func.__module__ == __name__)] print("Hint: call `docs(<function name>)` or `admin_functions()` for help on using the admin utils") +print("docs(<function name>) displays documentation on a given function") +print("admin_functions() lists all functions available to call within this module") |