#!/usr/bin/env python # -*- coding: utf-8 -*- # # netmerge-xmlrpc.py # # Copyright 2015 Neil Williams # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301, USA. # # """ Run once per output file to merge the new data with the existing device dictionary. Remember: importing a device dictionary replaces the entire dictionary with the new contents. """ import os import re import yaml import argparse import xmlrpclib def jinja2_to_dict(data_dict): """ This could be an XMLRPC routine itself at some point. """ if type(data_dict) is not str: return None data = {} data_dict = data_dict.replace('\n', '') data_dict = data_dict.replace('%}', '%}\n') for line in data_dict.replace('{% ', '').replace(' %}', '').split('\n'): if line == '': continue if line.startswith('extends'): base = line.replace('extends ', '') base = base.replace('"', "'").replace("'", '') data['extends'] = base if line.startswith('set '): key = line.replace('set ', '') key = re.sub(' = .*$', '', key) value = re.sub('^.* = ', '', line) data[key] = yaml.load(value) if 'extends' not in data: return None return data def main(args): parser = argparse.ArgumentParser(description='network map jinja2 merge') parser.add_argument( '--username', metavar='first.last', type=str, dest='username', required=True, help='superuser username') parser.add_argument( '--token', metavar='token', type=str, dest='token', required=True, help='superuser token') parser.add_argument( '--serverurl', metavar='url', type=str, dest='server', required=True, help='server holding existing content') parser.add_argument( '--hostname', metavar='NAME', type=str, dest='hostname', required=True, help='device hostname') args = parser.parse_args() if not os.path.exists('./merged'): os.mkdir('merged') output_file = os.path.join('output', "%s.jinja2" % args.hostname) if not os.path.exists(output_file): print >> sys.stderr, "Failed to find output file for %s" % args.hostname return 1 with open(output_file, 'r') as data: jinja_str = data.read() original = jinja2_to_dict(jinja_str) if not original: print >> sys.stderr, "Failed to parse output jinja string for %s" % args.hostname return 1 connection = xmlrpclib.ServerProxy("http://%s:%s@%s//RPC2" % (args.username, args.token, args.server)) jinja_str = connection.scheduler.export_device_dictionary(args.hostname) if not jinja_str: print >> sys.stderr, "Failed to find device dictionary for %s" % args.hostname return 1 map_data = jinja2_to_dict(str(jinja_str)) if not map_data: print >> sys.stderr, "Failed to parse existing jinja string for %s" % args.hostname return 1 original.update(map_data) with open('./merged/%s.jinja2' % args.hostname, 'w') as merge: merge.write("{%% extends '%s' %%}\n" % original['extends']) for key, value in original.items(): if key == 'extends': continue merge.write("{%% %s = '%s' %%}\n" % (key, value)) return 0 if __name__ == '__main__': import sys sys.exit(main(sys.argv))