From 3610288cbcbf4d1adedefa03166cd77ee15aad96 Mon Sep 17 00:00:00 2001 From: Narayan Desai Date: Sat, 29 Dec 2007 04:57:53 +0000 Subject: Refactor of bcfg2-admin (all modes moved to discrete modules in Bcfg2.Server.Admin git-svn-id: https://svn.mcs.anl.gov/repos/bcfg/trunk/bcfg2@4125 ce84e21b-d406-0410-9b95-82705330c041 --- src/lib/Server/Admin/Pull.py | 99 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 src/lib/Server/Admin/Pull.py (limited to 'src/lib/Server/Admin/Pull.py') diff --git a/src/lib/Server/Admin/Pull.py b/src/lib/Server/Admin/Pull.py new file mode 100644 index 000000000..ab334dbf9 --- /dev/null +++ b/src/lib/Server/Admin/Pull.py @@ -0,0 +1,99 @@ + +import binascii, lxml.etree, time +import Bcfg2.Server.Admin + +class Pull(Bcfg2.Server.Admin.Mode): + '''Pull mode retrieves entries from clients and integrates the information into the repository''' + __shorthelp__ = 'bcfg2-admin pull ' + __longhelp__ = __shorthelp__ + '\n\tIntegrate configuration information from clients into the server repository' + def __init__(self, configfile): + Bcfg2.Server.Admin.Mode.__init__(self, configfile) + + def __call__(self, args): + Bcfg2.Server.Admin.Mode.__call__(self, args) + self.PullEntry(args[0], args[1], args[2]) + + def PullEntry(self, client, etype, ename): + '''Make currently recorded client state correct for entry''' + # FIXME Pull.py is _way_ too interactive + sdata = self.load_stats(client) + if sdata.xpath('.//Statistics[@state="dirty"]'): + state = 'dirty' + else: + state = 'clean' + # need to pull entry out of statistics + sxpath = ".//Statistics[@state='%s']/Bad/ConfigFile[@name='%s']/../.." % (state, ename) + sentries = sdata.xpath(sxpath) + if not len(sentries): + self.errExit("Found %d entries for %s:%s:%s" % \ + (len(sentries), client, etype, ename)) + else: + print "Found %d entries for %s:%s:%s" % \ + (len(sentries), client, etype, ename) + maxtime = max([time.strptime(stat.get('time')) for stat in sentries]) + print "Found entry from", time.strftime("%c", maxtime) + statblock = [stat for stat in sentries \ + if time.strptime(stat.get('time')) == maxtime] + entry = statblock[0].xpath('.//Bad/ConfigFile[@name="%s"]' % ename) + if not entry: + self.errExit("Could not find state data for entry; rerun bcfg2 on client system") + cfentry = entry[-1] + + badfields = [field for field in ['perms', 'owner', 'group'] \ + if cfentry.get(field) != cfentry.get('current_' + field) and \ + cfentry.get('current_' + field)] + if badfields: + m_updates = dict([(field, cfentry.get('current_' + field)) \ + for field in badfields]) + print "got metadata_updates", m_updates + else: + m_updates = {} + + if 'current_bdiff' in cfentry.attrib: + data = False + diff = binascii.a2b_base64(cfentry.get('current_bdiff')) + elif 'current_diff' in cfentry.attrib: + data = False + diff = cfentry.get('current_diff') + elif 'current_bfile' in cfentry.attrib: + data = binascii.a2b_base64(cfentry.get('current_bfile')) + diff = False + else: + if not m_updates: + self.errExit("having trouble processing entry. Entry is:\n" \ + + lxml.etree.tostring(cfentry)) + else: + data = False + diff = False + + if diff: + print "Located diff:\n %s" % diff + elif data: + print "Found full (binary) file data" + if m_updates: + print "Found metadata updates" + + if not diff and not data and not m_updates: + self.errExit("Failed to locate diff or full data or metadata updates\nStatistics entry was:\n%s" % lxml.etree.tostring(cfentry)) + + try: + bcore = Bcfg2.Server.Core.Core({}, self.configfile) + except Bcfg2.Server.Core.CoreInitError, msg: + self.errExit("Core load failed because %s" % msg) + [bcore.fam.Service() for _ in range(10)] + while bcore.fam.Service(): + pass + m = bcore.metadata.get_metadata(client) + # find appropriate plugin in bcore + glist = [gen for gen in bcore.generators if + gen.Entries.get(etype, {}).has_key(ename)] + if len(glist) != 1: + self.errExit("Got wrong numbers of matching generators for entry:" \ + + "%s" % ([g.__name__ for g in glist])) + plugin = glist[0] + try: + plugin.AcceptEntry(m, 'ConfigFile', ename, diff, data, m_updates) + except Bcfg2.Server.Plugin.PluginExecutionError: + self.errExit("Configuration upload not supported by plugin %s" \ + % (plugin.__name__)) + # svn commit if running under svn -- cgit v1.2.3-1-g7c22