A local client for interfacing to the WebFaction web hosting server API.
The WebFaction API client is a local client for interfacing to the WebFaction web hosting server API. It provides class-based organization, convenience methods, script execution, and HTML-formatted run reporting.
It can be used as standalone module to execute a supplied script file or as an imported library module within individual script files.
Detailed documentation is available on http://wf-api-client.readthedocs.org/en/latest/.
|Author:||David J Cox|
Let me know what you think of it…
The client continues to be Python 2/3 compatible, as it should be. A full test suite has been added, which also doubles as an example of how to write a standalone script for the client.
What’s this all about?
WebFaction provides a perfectly cromulent RESTful API for their server accounts. It enables all aspects of server management to be executed remotely: CRUD actions for domains, websites, email, databases, etc. It even allows shell commands. Excellent!
However, despite its excellence, there are a few design decisions that cause misgivings for me:
- The WebFaction API uses positional arguments.
- When working with remote servers, I prefer commands to be as explicit as possible, because like Unix, APIs can be unforgiving. This client uses keyword arguments to guard against a slip of concentration wiping something important out. It translates the keyword arguments into positional ones for each API call.
- The WebFaction API has small inconsistencies in calling convention.
- This is a nitpick, but one that’s important when remotely administering servers. Some API calls define collections using lists. Others define collections using positional arguments only. Once again, a mistake waiting to be made if a call signature is recalled incorrectly. This client uses lists for all collections and unwraps them back into individual positional arguments for those API calls that require it.
In addition to these translation functions, the WebFaction API client provides additional utility similar to other IT automation solutions like Ansible, Salt, etc, by providing batching, parallelism, and reporting, described as follows.
Functional groups are implemented as classes with API calls grouped as methods. Working with descriptive class instances makes complicated scripting easier, especially when driving more than one server or using more than one worker thread. In addition to atomic methods, batched convenience methods have been added, for e.g. creating/deleting RFC 2142 email prefixes in one call.
In addition to batch methods, convenience methods are used to speed script execution by performing client-side evaluation to avoid unnecessary remote API calls. Creation/deletion calls are compared against a single inventory call to ensure that entities exist before attempting deletion or do not exist before attempting creation. If not, client errors are reported.
Why have an API if it’s not being scripted against? The client provides scripting two ways: Scripts can be passed directly to the client in a standalone module call, or the module can be imported as a library module within standalone scripts. See below for examples of both approaches.
HTML-formatted Run Reporting
Since RESTful services are stateless, they can’t (shouldn’t) provide history. This client does. Every method call resulting in a remote API call returns the status, datetime, API call name, and call result to a log function. The running tally of logged actions are collected and reported as a HTMl report file. Call results are color-coded green for ‘success’ and red for ‘failure’. Elementary!
A full test suite is provided in the wfapiclienttests.py file. It is standalone script and, so, doubles as a fine example for standalone scripts. The tests must be run against a live, accessible WeFaction server using valid credentials. The tests are not idempotent but can be considered nearly so in that all test actions against the server will not cause side effects for the existing configuration and all test create and update actions are deleted afterward. Should some event prevent successful completion of the tests, all test objects created on the server are obviously identifiable with some variation of ‘wf_test’ pre-pended to their name and should be considered safe to delete manually.
Tests are executed like so:
python wfapiclienttests.py "username" "password" "/path/to/report.html"
Standalone scripts import the module as a library and are responsible for instantiating the Runner class to log results and write out the run report. It is more flexible in that multiple runner objects can be created to work on different servers at one time logging either to separate reports or to one shared report. Standalone scripts are structured like this:
"""`create_emails` script""" import wfapiclient as wf runner1 = wf.Runner() runner2 = wf.Runner() #WebFaction automagically identifies target server by username/password. runner1.login_to_server("first_username", "first_password") runner2.login_to_server("second_username", "second_password") #Server objects are tied to runner instances for call execution and logging. email1 = wf.Email(runner1) email1.create_emails(domain="first.example.com", targets="firstname.lastname@example.org") email2 = wf.Email(runner2) email2.create_emails(domain="second.example.com", targets="email@example.com") #Either write report to separate report files... runner1.write_report_to_file("/tmp/create_emails1.html") runner2.write_report_to_file("/tmp/create_emails2.html") #...or write (append) reports to one `shared` file. runner1.write_report_to_file("/tmp/create_emails_shared.html") runner2.write_report_to_file("/tmp/create_emails_shared.html") #EOF - `create_emails`
Direct module calls are invoked like this:
python wfapiclient.py "username" "password" \ --scriptfile=/home/user/scripts/create_emails \ --reportfile=/tmp/create_emails.html
Scripts for importation by the module call methods directly using Python syntax. The run report is automatically generated using a supplied destination file name. Imported scripts are structured like this:
"""`create_emails` script""" #Class object creation requires `self` reference to Runner(). email = Email(self) email.create_emails(domain="example.com", targets="firstname.lastname@example.org") #EOF - `create_emails`
That’s it. Have fun.
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
|Filename, size||File type||Python version||Upload date||Hashes|
|Filename, size wf_api_client-1.0.1-py3-none-any.whl (17.3 kB)||File type Wheel||Python version py3||Upload date||Hashes View hashes|
|Filename, size wf-api-client-1.0.1.tar.gz (14.1 kB)||File type Source||Python version None||Upload date||Hashes View hashes|
Hashes for wf_api_client-1.0.1-py3-none-any.whl