Add documentation to admin_utils functions 41/72141/3
authorSawyer Bergeron <sbergeron@iol.unh.edu>
Wed, 3 Mar 2021 19:06:07 +0000 (14:06 -0500)
committerSawyer Bergeron <sbergeron@iol.unh.edu>
Wed, 17 Mar 2021 16:30:48 +0000 (12:30 -0400)
Signed-off-by: Sawyer Bergeron <sbergeron@iol.unh.edu>
Change-Id: I27204f49513b3d646776261ed869d9f4d5c6fd64
Signed-off-by: Sawyer Bergeron <sbergeron@iol.unh.edu>
src/dashboard/admin_utils.py

index 76db762..d97b6ed 100644 (file)
@@ -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")