-#!/usr/bin/env python2.5
+#!/usr/bin/env python
"""
invirt-getconf [-f FILE] KEY prints the configuration the option named KEY from
from sys import argv, exit, stderr
from optparse import OptionParser
-class invirt_exception( Exception ): pass
+class invirt_exception(Exception): pass
-def main( argv ):
+def main(argv):
try:
- parser = OptionParser()
- parser.add_option('-f', '--file', default = '/etc/invirt/master.yaml',
- help = 'the configuration file to read from')
- options, args = parser.parse_args()
+ parser = OptionParser(usage = '%prog [options] key',
+ description = __doc__.strip().split('\n\n')[0])
+ parser.add_option('-s', '--src',
+ default = '/etc/invirt/master.yaml',
+ help = 'the source YAML configuration file to read from')
+ parser.add_option('-c', '--cache',
+ default = '/var/lib/invirt/invirt.json',
+ help = 'path to the JSON cache')
+ parser.add_option('-r', '--refresh',
+ action = 'store_true',
+ help = 'force the cache to be regenerated')
+ opts, args = parser.parse_args()
try: [key] = args
- except: raise invirt_exception( __doc__ )
+ except: raise invirt_exception(__doc__.strip())
- conf = load()
+ conf = load(opts.src, opts.cache, opts.refresh)
components = key.split('.')
- for i, component in enumerate( components ):
- progress = lambda: '.'.join( components[:i] )
- if type( conf ) not in [ dict, list ]:
+ for i, component in enumerate(components):
+ progress = '.'.join(components[:i])
+ if type(conf) not in [dict, list]:
raise invirt_exception(
- 'prematurely arrived at an atomic datum in the tree:\n'
- '%s has no children' % progress() )
- if type( conf ) == list:
- try: component = int( component )
+ '%s: node has no children (atomic datum)' % progress)
+ if type(conf) == list:
+ try: component = int(component)
except: raise invirt_exception(
- '%s is a list, requires an integral path component '
- 'but got "%s"' % ( progress(), component ) )
- try: conf = conf[ component ]
+ '%s: node a list; integer path component required, '
+ 'but got "%s"' % (progress, component))
+ try: conf = conf[component]
except KeyError: raise invirt_exception(
- '"%s" not in "%s"' % ( component, progress() ) )
+ '%s: key "%s" not found' % (progress, component))
+ except IndexError: raise invirt_exception(
+ '%s: index %s out of range' % (progress, component))
print conf
- except invirt_exception, ex:
+ except (invirt_exception, OSError), ex:
print >> stderr, ex
return 1
-if __name__ == '__main__': exit( main( argv ) )
+if __name__ == '__main__':
+ exit(main(argv))
# vim:et:sw=4:ts=4
-import yaml
+import json, yaml
+from os import error, makedirs
+from os.path import dirname, getmtime
-default_path = '/etc/invirt/master.yaml'
+default_src_path = '/etc/invirt/master.yaml'
+default_cache_path = '/var/lib/invirt/invirt.json'
try: default_loader = yaml.CSafeLoader
except: default_loader = yaml.SafeLoader
-def load( path = default_path ):
- return yaml.load( file(path), default_loader )
+def wrap(rsrc, func):
+ "Utility to that emulates with Python 2.5's `with closing(rsrc)`."
+ try: return func(rsrc)
+ finally: rsrc.close()
+
+def load(src_path = default_src_path,
+ cache_path = default_cache_path,
+ force_refresh = False):
+ """
+ Try loading the configuration from the faster-to-load JSON cache at
+ cache_path. If it doesn't exist or is outdated, load the configuration
+ instead from the original YAML file at src_path and regenerate the cache.
+ I assume I have the permissions to write to the cache directory.
+ """
+ if force_refresh:
+ do_refresh = True
+ else:
+ src_mtime = getmtime(src_path)
+ try: cache_mtime = getmtime(cache_path)
+ except OSError: do_refresh = True
+ else: do_refresh = src_mtime > cache_mtime
+
+ if do_refresh:
+ # reload the source and regenerate the cache
+ cfg = wrap(file(src_path), lambda f: yaml.load(f, default_loader))
+ wrap(file(cache_path, 'w'), lambda f: f.write(json.write(cfg)))
+ else:
+ cfg = wrap(file(cache_path), lambda f: json.read(f.read()))
+ return cfg
# vim:et:sw=4:ts=4