January 22, 2019
Everyday DevOps: A Look at Gooey
This tool brings simplicity to Python complexity.
In my day-to-day life, I try to figure out little ways to become more efficient and consistent while solving the problems that are in front of me. In my personal life, these problems are usually more self-inflicted, such as creating customizable holiday lights or graphing fermentation temperatures for home-brewing. Professionally, this often looks more like creating reusable templates and writing scripts to improve the team’s efficiency in mundane and repeatable tasks.
Having been lucky enough to stumble into Python a few years back on the advice of a few friends, I’m well-equipped to use this language as a tool in a DevOps model to tackle repeatable tasks. Lately, I’ve been trying to write things using Gooey as a front end to make my scripts more accessible.
Learning about Gooey
Gooey is a Python package that aims to “turn (almost) any Python command line program into a full GUI application with one line.” As someone who does not have a programming background, my first attempts at building any sort of simple GUI for my scripts never looked very nice or had the functionality I wanted to implement. Most of my scripts ended up using some combination of command line flags, text file, CSV or Excel file input/output.
Like many other network engineers/Linux users, I’m quite comfortable in the command line, so frequently, my tools ended up requiring the use of multiple input files and several flags via the CLI. While this worked fine for me, I found that as I shared tools with the team, there were frequently questions about usage, misunderstandings about a flag’s intent or sometimes even low adoption because people just gave up.
This was particularly true for folks who just wanted to be “consumers” of the tool and didn’t really have any interest in learning or troubleshooting Python. After hearing about Gooey on the Python Bytes podcast, I realized it presented a good opportunity to learn something new and improve the usability of my scripts for my wider audience.
How Gooey Works
Gooey itself is rather simple to implement once installed. As shown in the GitHub documentation, Gooey is attached to your code via a decorator on the method that you would have previously used with argparse.
Within that method, you then set up a GooeyParser, add arguments and select any number of pre-canned widgets to provide input to the script. The widgets are essentially what make up the components of the user interface that you are trying to create. I’ve found command tasks such as a file-chooser, date-chooser, input field or list box to be exceptionally useful in streamlining even the most basic script into something that’s simple for anyone to use.
Additional advanced features such as input validation, dynamic-value usage and even custom icons are also available and well documented, even though I won’t dive into them here. In order to illustrate a simple script, I’ve rewritten a piece of a simple tool I created a while back.
A Closer Look at My Script
My original script was written many years back when I was just learning Python and was getting sick of having to reread documentation every time I wanted to figure out the correct values to use for Dynamic Host Configuration Protocol Option 43. DHCP Option 43, for the uninitiated, is a method in which clients and servers can exchange vendor-specific information via DHCP requests. Many networking vendors such as Aruba and Cisco use Option 43 during a lightweight access point’s discovery process to inform the AP about the address of the wireless controller to which it should be joining.
Utilizing this feature gives lots of flexibility to the end user, allowing them to designate specific controllers per DHCP scope if there are multiple in the organization. It also allows unprimed APs to “just work,” straight out of the box, when placed in the correct subnet (albeit with some additional configuration after the AP shows up on the controller). This is invaluable for both greenfield deployments as well as refresh/replacements down the line.
Additionally, this script provided an easy way for more junior and non-wireless engineers to generate the correct Option 43 values when deploying or troubleshooting without having to pull in a wireless engineer. As a side note, I’ve always found that solving small problems or irritations like this is the best way to learn (or improve aptitude in) a programming language. Foundational courses are fantastic, but nothing motivates and gives ultimate satisfaction like practical application of what you’ve learned. I’ve also used that approach here in the rewritten version, which now uses Gooey. The full code can be found over at GitHub, but I will detail some elements below.
As mentioned previously, the Gooey decorator was added to my main method and then I created a parser with a simple description. This script is only asking for a simple text input, so an argument was added named “Controllers” with some help text to let the user know what format was expected. All the arguments — in this case, only one — were collected in the object “args,” allowing the specific data per argument to be accessible by other pieces of the script.
In this case, I have “args.Controllers” providing the user input to another method in the script, which does a bit of cleanup and sanitization of the data. The “sanitize” method creates a list, splits the input string into chunks using a comma as the delimiter, strips out white spaces and then adds each chunk in to the list. For some additional quick sanitization, I’m using the IP address package to check that each of the items in the list is a “valid” IPv4 address.
In the quick usage here, I’m not checking that the address is routable or truly useable, just that it follows the syntax of X.X.X.X, so your mileage may vary if odd input is given. If there is an issue, we print an error and exit, otherwise the method will return our list of IP addresses.
There is a bit of formatting done via a single line for loop to make the script’s output slightly more aesthetically pleasing. While not strictly necessary, I wanted the output to look more like what a human might write down rather than just printing the list itself.
The Option 43 Value
Finally, we send the list of IPs to the method that will calculate the Option 43 value for us and print the returned value. Cisco’s Option 43 implementation in this case specifies type, length and value in a mostly straightforward manner with all values in hex. The type will always be “f1,” the length is the number of controller management IP addresses multiplied by four, and the value is each of the those addresses also converted to hex.
The method uses list comprehension to create a new list that consists of the hexadecimal equivalent values of our previously dotted quad notation IP address. Each IP is broken out by the individual dotted quad value, converted to hexadecimal and then joined back together without any spaces. This is done for each value in the original list, resulting in our new desired list of hex values.
From there, we set our static “t” value, use the previously populated “wlc_count” variable to do the multiplication and conversion to hex for our “l” value, and then join all elements in our list of hex IPs to create a single string. Finally, “t,” “l” and “v” values are concatenated and returned to the script.
The final line in the main method prints our desired value in the main Gooey window for the end user to use as needed.
The Final Output
When the program is run, a simple user interface is presented, hiding all the complex methods described above. The user has a single user input box for IP addresses and two buttons at the bottom to either run the script or cancel it (as seen in the screenshot at the beginning of this post). After running the script, the output mentioned above is shown in the main window.
Again, the output is meant to be human readable and convey not only the results but also the user input and what the script thinks it saw based on the user input. While not foolproof, this at least gives the end user a chance to scrutinize their own input in case something was keyed in incorrectly.
Gooey also has a nice feature where the user can select the “Edit” button to effectively rerun the script by giving another set of input values. In this script, it would probably only be used to correct a bad value or generate multiple Option 43 strings, but it could be used for additional workflow considerations in other implementations.
Gooey Keeps It Simple
Gooey is quickly becoming my go-to for scripts that require basic user interaction. It makes sharing tools with my teammates much easier, regardless of skill level or interest in Python. It’s even solved one of my much-hated problems with easy date and time input (see the DateChooser widget).
I encourage anyone writing CLI-driven Python scripts to give Gooey a shot and see if you can spruce up your code like I have. I’d also love to hear any feedback if this helps you or you’re working on something that would be a perfect fit. I wish you the best of luck in your DevOps Gooey endeavors.