#!/usr/bin/env python from getopt import getopt, GetoptError from os import popen, chmod, unlink from sys import argv, exit, exc_info from string import join from tempfile import mktemp from traceback import extract_tb from elementtree.ElementTree import Element, XML, tostring from sss.ssslib import comm_lib from Bcfg2.Client.Debian import Debian def RunProbe(probe): ret = Element("probe-data", name=probe.attrib['name'], source=probe.attrib['source']) script = open(mktemp(), 'w+') script.write("#!%s\n"%(probe.attrib.get('interpreter', '/bin/sh'))) script.write(probe.text) script.close() chmod(script.name, 0755) ret.text = popen(script.name).read() unlink(script.name) return ret def dgetopt(arglist, opt, vopt): r = {} for o in opt.values() + vopt.values(): r[o] = False gstr = join(opt.keys()) + join([x+':' for x in vopt.keys()]) try: (o, a) = getopt(arglist, gstr) except GetoptError, g: print g print "bcfg2 Usage:" for (k,v) in opt.iteritems(): print " -%s %s"%(k,v) for (k,v) in vopt.iteritems(): print " -%s <%s>"%(k,v) exit(1) for (gopt,garg) in o: option = gopt[1:] if opt.has_key(option): r[opt[option]] = True else: r[vopt[option]] = garg return r if __name__ == '__main__': # parse command line options options = {'v':'verbose','q':'quick', 'd':'debug', 'n':'dryrun', 'B':'build', 'p':'paranoid'} doptions = {'b':'bundle', 'f':'file', 'c':'cache'} setup = dgetopt(argv[1:], options, doptions) print setup # connect to bcfg2d comm = comm_lib() h = comm.ClientInit("bcfg2") # get probes comm.SendMessage(h, "") data = comm.RecvMessage(h) if setup['verbose']: print data probes = XML(data) # execute probes probedata = map(RunProbe, probes.findall(".//probe")) # upload probe responses cpd = Element("probe-data") map(lambda x:cpd.append(x), probedata) if setup['verbose'] : print tostring(cpd) comm.SendMessage(h, tostring(cpd)) r = comm.RecvMessage(h) # get config comm.SendMessage(h, "") r = comm.RecvMessage(h) if setup['cache']: try: open(setup['cache'], 'w').write(r) except: print "failed to write config cache file %s"%(setup['cache']) cfg = XML(r) if cfg.tag == 'error': print "got error from server" exit(1) # initialize toolset stuff toolset = Debian(cfg, setup) # verify state unexamined = cfg.getchildren() structurestate = {} entrystate = {} while unexamined: r = unexamined.pop() unexamined += r.getchildren() if r.tag in ['Bundle', 'Image']: structurestate[r] = False continue try: method = getattr(toolset, "Verify%s"%(r.tag)) except: print ":failed: for %s :failed:"%(tostring(r)) continue # verify state and stash value in state entrystate[r] = method(r) if setup['debug']: print r.attrib['name'], entrystate[r] # now we go back to check structures for structure in cfg.getchildren(): for child in structure.getchildren(): if not entrystate[child]: break structurestate[structure] = True for entry in [k for (k,v) in entrystate.iteritems() if not v]: method = getattr(toolset, "Install%s"%(entry.tag)) try: entrystate[entry] = method(entry) except: print "Install failed for %s"%(tostring(entry)) (t,v,tb) = exc_info() print "Unexpected failure in Install:" for line in extract_tb(tb): print "File %s, line %i, in %s\n %s\n"%(line) print "%s: %s\n"%(t,v) del t,v,tb for structure in structurestate.keys(): if structurestate[structure]: continue for entry in structure.getchildren(): entrystate[entry] = getattr(toolset, "Verify%s"%(entry.tag)) states = map(lambda x:entrystate[x], structure.getchildren()) if False not in states: structurestate[structure] = True #print entrystate print "good:", for k,v in entrystate.iteritems(): if v: print k.attrib['name'], # install config # upload statistics comm.ClientClose(h)