From: Yang Zhang Date: Mon, 28 Jul 2008 16:25:19 +0000 (-0400) Subject: - added timestamp-based JSON caching of configuration for faster loading X-Git-Tag: sipb-xen-base/8.8~1 X-Git-Url: http://xvm.mit.edu/gitweb/invirt/packages/invirt-base.git/commitdiff_plain/95eb488e71743cadb53e3d1af9e0d7ce5414ce9e - added timestamp-based JSON caching of configuration for faster loading - exposed (more) options to command-line frontend - improved error messages/handling/help - removed all python 2.5-isms - reformatted to fit project style conventions svn path=/trunk/packages/sipb-xen-base/; revision=771 --- diff --git a/files/usr/sbin/invirt-getconf b/files/usr/sbin/invirt-getconf index c468499..d503dea 100755 --- a/files/usr/sbin/invirt-getconf +++ b/files/usr/sbin/invirt-getconf @@ -1,4 +1,4 @@ -#!/usr/bin/env python2.5 +#!/usr/bin/env python """ invirt-getconf [-f FILE] KEY prints the configuration the option named KEY from @@ -19,39 +19,49 @@ from invirt.config import load 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 diff --git a/files/usr/share/python-support/sipb-xen-base/invirt/config.py b/files/usr/share/python-support/sipb-xen-base/invirt/config.py index ea4bf4e..dab9f20 100644 --- a/files/usr/share/python-support/sipb-xen-base/invirt/config.py +++ b/files/usr/share/python-support/sipb-xen-base/invirt/config.py @@ -1,11 +1,41 @@ -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