linode-api-python-part-3

12 Jun 2008

Ataraxia Consulting


In part 1 I discussed the creation of the base api, in part 2 the creation of the interactive shell, and now in part 3 the creation of the previously mentioned command line driver. To wet your whistle here’s how you could create a specific A record query it and update it

tjlappy:linode tjfontaine$ ./shell.py --domainResourceSave --resourceid=0 --domainid=14 --name=dynamic --type=a --target=192.168.0.100 --priority=0 --ttl_sec=0 --weight=0 --port=0
{
  "ResourceID": 6719
}
tjlappy:linode tjfontaine$ ./shell.py --domainResourceGet --resourceid=6719
{
  "DOMAINID": 14, 
  "NAME": "dynamic", 
  "RESOURCEID": 6719, 
  "TARGET": "192.168.0.100", 
  "TYPE": "a", 
  "TTL_SEC": 0
}
tjlappy:linode tjfontaine$ ./shell.py --domainResourceSave --resourceid=6719 --domainid=14 --name=dynamic --type=a --target=192.168.0.101 --priority=0 --ttl_sec=0 --weight=0 --port=0
{
  "ResourceID": 6719.0
}
tjlappy:linode tjfontaine$ ./shell.py --domainResourceGet --resourceid=6719
{
  "DOMAINID": 14, 
  "NAME": "dynamic", 
  "RESOURCEID": 6719, 
  "TARGET": "192.168.0.101", 
  "TYPE": "a", 
  "TTL_SEC": 0
}

Here are the goals I had for the command line driver, in no particular order:

  • dynamically generated list of valid actions (without ugly hacks that depend on dir and sanitizing names)
  • dynamically generated list of valid parameters
  • useful getopt style parsing
  • dynamically generated help messages

There are some fundamental changes to the base api to achieve this. First, I removed __api_required, I knew from the get go that this functionality should have been in __api_request there was no need to chain them. Second, every argument listed in the api is now considered to be required. This second change seems like quite a drastic move, the rationale is this:

  • when adding a new api method you only want to have to define parameters once (this is to fulfill goal 2 on above list)
  • when adding parameters the results should be obvious and not have arbitrary notation/syntax indicating optional from required
  • even if a parameter is listed as optional not including it will reset that field to the default value (but you may think you’re preserving the previous value).

Now todays trickery/hackery, you have to be able to discern between when a class is compiled and decorated versus when decorators are invoked at runtime. Last night when I started the refactoring I initially put the population of the commands and parameter lists inside the wrapper method. But this will only be reached when the method is actually invoked (of course). However, a method is decorated at compile time, so my work around was to create a class ApiInfo with class variables, so long as ApiInfo is compiled before Api I can add populate the parameter and command lists.

Here’s what I end up being able to do:

tjlappy:linode tjfontaine$ ./shell.py --help
shell.py --<api action> [--parameter1=value [--parameter2=value [...]]]
Valid Actions
  --domainDelete
  --domainGet
  --domainList
  --domainResourceDelete
  --domainResourceGet
  --domainResourceList
  --domainResourceSave
  --domainSave
  --linodeList
Valid Named Parameters
  --domain=
  --domainid=
  --master_ips=
  --name=
  --port=
  --priority=
  --refresh_sec=
  --resourceid=
  --retry_sec=
  --soa_email=
  --status=
  --target=
  --ttl_sec=
  --type=
  --weight=

Shnazzy, plenty of room for improvement of course. Being able to pull out a short help string from __doc__ for each valid command would be pretty, and making –help from the command line look to see if an action is defined and then display the whole __doc__ from that method. Also there’s no reason that irgeek’s high-level-commands can’t be added to the right places in ApiInfo to be populated, so you’ll be able to get his recent method additions such as domainResourceUpdate which behaves more like you’d want if you’re planning on doing dyndns with linode.

As usual the code is available for you to git clone git://github.com/tjfontaine/linode-python.git and for you to browse at http://github.com/tjfontaine/linode-python