summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorNarayan Desai <desai@mcs.anl.gov>2004-10-11 20:16:38 +0000
committerNarayan Desai <desai@mcs.anl.gov>2004-10-11 20:16:38 +0000
commitd9bf1e8a313e6daac6cdc4f045aea20c052443f2 (patch)
tree0d6e8a31c67a08553cfd93a4125d270a76defba5 /src
parent2ff1213164f27c94468dc02818e748cfc31d5082 (diff)
downloadbcfg2-d9bf1e8a313e6daac6cdc4f045aea20c052443f2.tar.gz
bcfg2-d9bf1e8a313e6daac6cdc4f045aea20c052443f2.tar.bz2
bcfg2-d9bf1e8a313e6daac6cdc4f045aea20c052443f2.zip
refactor clientstate code into the toolsets (will allow better two-way implementation)
(Logical change 1.84) git-svn-id: https://svn.mcs.anl.gov/repos/bcfg/trunk/bcfg2@401 ce84e21b-d406-0410-9b95-82705330c041
Diffstat (limited to 'src')
-rw-r--r--src/lib/Client/Toolset.py117
1 files changed, 110 insertions, 7 deletions
diff --git a/src/lib/Client/Toolset.py b/src/lib/Client/Toolset.py
index 583c22e7b..58ae8fb00 100644
--- a/src/lib/Client/Toolset.py
+++ b/src/lib/Client/Toolset.py
@@ -5,6 +5,9 @@ from os import chown, chmod, lstat, mkdir, stat, system, unlink, rename, readlin
from pwd import getpwuid, getpwnam
from stat import *
from string import join, split
+from sys import exc_info
+from time import asctime, localtime
+from traceback import extract_tb
def print_failure():
if '-v' in argv: print "\033[60G[\033[1;31mFAILED\033[0;39m]\r"
@@ -46,12 +49,119 @@ class Toolset(object):
def __init__(self, cfg, setup):
self.setup = setup
+ self.cfg = cfg
+ self.states = {}
+ self.structures = {}
+ self.modified = []
+ self.extra = []
if self.__important__:
for c in cfg.findall(".//ConfigFile"):
for name in self.__important__:
if c.get("name") == name:
self.InstallConfigFile(c)
+ def LogFailure(self, area, entry):
+ '''Print tracebacks in unexpected cases'''
+ print "Failure in %s for entry: %s"%(area, tostring(entry))
+ (t,v,tb) = exc_info()
+ 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
+
+ # These next functions form the external API
+
+ def Inventory(self):
+ # build initial set of states
+ unexamined = map(lambda x:(x,[]), self.cfg.getchildren())
+ while unexamined:
+ (r, modlist) = unexamined.pop()
+ if r.tag not in ['Bundle', 'Independant']:
+ self.VerifyEntry(r, modlist)
+ else:
+ modlist = [x.attrib['name'] for x in r.getchildren() if x.tag == 'ConfigFile']
+ unexamined += map(lambda x:(x,modlist), r.getchildren())
+ self.structures[r] = False
+
+ for structure in self.cfg.getchildren():
+ self.CheckStructure(structure)
+
+ # TwoWay: build list of "extra configs"
+ #e = self.toolset.FindElements()
+ #known = self.states.keys()
+ #for entry in e:
+ # if not filter(lambda x:ElementMatch(x, entry), known):
+ # self.extra.append(entry)
+ #print self.extra
+
+ def CheckStructure(self, structure):
+ '''Check structures with bundle verification semantics'''
+ if structure in self.modified:
+ self.modified.remove(structure)
+ if structure.tag == 'Bundle':
+ # check for clobbered data
+ modlist = [x.attrib['name'] for x in structure.getchildren() if x.tag == 'ConfigFile']
+ for entry in structure.getchildren():
+ self.VerifyEntry(entry, modlist)
+ try:
+ state = map(lambda x:self.states[x], structure.getchildren())
+ if False not in state:
+ self.structures[structure] = True
+ except KeyError, k:
+ print "State verify evidently failed for %s"%(k)
+ self.structures[structure] = False
+
+ def Install(self):
+ self.modified = [k for (k,v) in self.structures.iteritems() if not v]
+ for entry in [k for (k,v) in self.states.iteritems() if not v]:
+ self.InstallEntry(entry)
+
+ def Commit(self):
+ '''Commit pending changes to the system. This method allows for interrelated
+ operations to be executed concurrently'''
+ return
+
+ def GenerateStats(self):
+ '''Generate XML summary of execution statistics'''
+ stats = Element("Statistics")
+ SubElement(stats, "Structures", good=str(len([k for k,v in self.structures.iteritems() if v])), \
+ bad=str(len([k for k,v in self.structures.iteritems() if not v])))
+ SubElement(stats, "Entries", good=str(len([k for k,v in self.states.iteritems() if v])), \
+ bad=str(len([k for k,v in self.states.iteritems() if not v])))
+ if len([k for k,v in self.structures.iteritems() if not v]) == 0:
+ stats.attrib['state'] = 'clean'
+ else:
+ stats.attrib['state'] = 'dirty'
+ stats.attrib['time'] = asctime(localtime())
+ return stats
+
+ # the next two are dispatch functions
+
+ def VerifyEntry(self, entry, modlist = []):
+ '''Dispatch call to Verify<tagname> and save state in self.states'''
+ try:
+ method = getattr(self, "Verify%s"%(entry.tag))
+ # verify state and stash value in state
+ if entry.tag == 'Package':
+ self.states[entry] = method(entry, modlist)
+ else:
+ self.states[entry] = method(entry)
+
+ if self.setup['debug']:
+ print entry.attrib['name'], self.states[entry]
+ except:
+ self.LogFailure("Verify", entry)
+
+ def InstallEntry(self, entry):
+ '''Dispatch call to self.Install<tagname>'''
+ try:
+ method = getattr(self, "Install%s"%(entry.tag))
+ self.states[entry] = method(entry)
+ except:
+ self.LogFailure("Install", entry)
+
+ # All remaining operations implement the mechanics of POSIX cfg elements
+
def VerifySymLink(self, entry):
try:
s = readlink(entry.attrib['from'])
@@ -171,10 +281,3 @@ class Toolset(object):
print e
return False
- def FindConfig(self):
- pass
-
- def Commit(self, entrystate):
- '''Commit pending changes to the system. This method allows for interrelated
- operations to be executed concurrently'''
- return