summaryrefslogtreecommitdiffstats
path: root/src/lib/Bcfg2/Client/Frame.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/Bcfg2/Client/Frame.py')
-rw-r--r--src/lib/Bcfg2/Client/Frame.py210
1 files changed, 130 insertions, 80 deletions
diff --git a/src/lib/Bcfg2/Client/Frame.py b/src/lib/Bcfg2/Client/Frame.py
index 9ad669ad6..2218b890b 100644
--- a/src/lib/Bcfg2/Client/Frame.py
+++ b/src/lib/Bcfg2/Client/Frame.py
@@ -17,32 +17,6 @@ def cmpent(ent1, ent2):
return cmp(ent1.get('name'), ent2.get('name'))
-def promptFilter(prompt, entries):
- """Filter a supplied list based on user input."""
- ret = []
- entries.sort(cmpent)
- for entry in entries[:]:
- if 'qtext' in entry.attrib:
- iprompt = entry.get('qtext')
- else:
- iprompt = prompt % (entry.tag, entry.get('name'))
- try:
- # py3k compatibility
- try:
- ans = raw_input(iprompt.encode(sys.stdout.encoding, 'replace'))
- except NameError:
- ans = input(iprompt)
- if ans in ['y', 'Y']:
- ret.append(entry)
- except EOFError:
- # python 2.4.3 on CentOS doesn't like ^C for some reason
- break
- except:
- print("Error while reading input")
- continue
- return ret
-
-
def matches_entry(entryspec, entry):
# both are (tag, name)
if entryspec == entry:
@@ -71,7 +45,7 @@ def passes_black_list(entry, blacklist):
for be in blacklist]
-class Frame:
+class Frame(object):
"""Frame is the container for all Tool objects and state information."""
def __init__(self, config, setup, times, drivers, dryrun):
self.config = config
@@ -84,7 +58,7 @@ class Frame:
self.whitelist = []
self.blacklist = []
self.removal = []
- self.logger = logging.getLogger("Bcfg2.Client.Frame")
+ self.logger = logging.getLogger(__name__)
for driver in drivers[:]:
if driver not in Bcfg2.Client.Tools.drivers and \
isinstance(driver, str):
@@ -124,33 +98,74 @@ class Frame:
self.logger.info([tool.name for tool in self.tools])
# find entries not handled by any tools
- problems = [entry for struct in config for \
- entry in struct if entry not in self.handled]
+ self.unhandled = [entry for struct in config
+ for entry in struct
+ if entry not in self.handled]
- if problems:
+ if self.unhandled:
self.logger.error("The following entries are not handled by any tool:")
- self.logger.error(["%s:%s:%s" % (entry.tag, entry.get('type'), \
- entry.get('name')) for entry in problems])
- self.logger.error("")
- entries = [(entry.tag, entry.get('name'))
- for struct in config for entry in struct]
+ for entry in self.unhandled:
+ self.logger.error("%s:%s:%s" % (entry.tag, entry.get('type'),
+ entry.get('name')))
+
+ self.find_dups(config)
+
pkgs = [(entry.get('name'), entry.get('origin'))
- for struct in config for entry in struct if entry.tag == 'Package']
- multi = []
- for entry in entries[:]:
- if entries.count(entry) > 1:
- multi.append(entry)
- entries.remove(entry)
- if multi:
- self.logger.debug("The following entries are included multiple times:")
- self.logger.debug(["%s:%s" % entry for entry in multi])
- self.logger.debug("")
+ for struct in config
+ for entry in struct
+ if entry.tag == 'Package']
if pkgs:
self.logger.debug("The following packages are specified in bcfg2:")
self.logger.debug([pkg[0] for pkg in pkgs if pkg[1] == None])
self.logger.debug("The following packages are prereqs added by Packages:")
self.logger.debug([pkg[0] for pkg in pkgs if pkg[1] == 'Packages'])
+ def find_dups(self, config):
+ entries = dict()
+ for struct in config:
+ for entry in struct:
+ for tool in self.tools:
+ if tool.handlesEntry(entry):
+ pkey = tool.primarykey(entry)
+ if pkey in entries:
+ entries[pkey] += 1
+ else:
+ entries[pkey] = 1
+ multi = [e for e, c in entries.items() if c > 1]
+ if multi:
+ self.logger.debug("The following entries are included multiple times:")
+ for entry in multi:
+ self.logger.debug(entry)
+
+ def promptFilter(self, prompt, entries):
+ """Filter a supplied list based on user input."""
+ ret = []
+ entries.sort(cmpent)
+ for entry in entries[:]:
+ if entry in self.unhandled:
+ # don't prompt for entries that can't be installed
+ continue
+ if 'qtext' in entry.attrib:
+ iprompt = entry.get('qtext')
+ else:
+ iprompt = prompt % (entry.tag, entry.get('name'))
+ try:
+ # py3k compatibility
+ try:
+ ans = raw_input(iprompt.encode(sys.stdout.encoding,
+ 'replace'))
+ except NameError:
+ ans = input(iprompt)
+ if ans in ['y', 'Y']:
+ ret.append(entry)
+ except EOFError:
+ # python 2.4.3 on CentOS doesn't like ^C for some reason
+ break
+ except:
+ print("Error while reading input")
+ continue
+ return ret
+
def __getattr__(self, name):
if name in ['extra', 'handled', 'modified', '__important__']:
ret = []
@@ -190,17 +205,26 @@ class Frame:
self.whitelist = [x for x in self.whitelist if x not in b_to_rem]
# take care of important entries first
- if not self.dryrun and not self.setup['bundle']:
- for cfile in [cfl for cfl in self.config.findall(".//Path") \
- if cfl.get('name') in self.__important__ and \
- cfl.get('type') == 'file']:
- if cfile not in self.whitelist:
+ if not self.dryrun:
+ for cfile in self.config.findall(".//Path"):
+ if (cfile.get('name') not in self.__important__ or
+ cfile.get('type') != 'file' or
+ cfile not in self.whitelist):
+ continue
+ parent = cfile.getparent()
+ if ((parent.tag == "Bundle" and
+ ((self.setup['bundle'] and
+ parent.get("name") not in self.setup['bundle']) or
+ (self.setup['skipbundle'] and
+ parent.get("name") in self.setup['skipbundle']))) or
+ (parent.tag == "Independent" and
+ (self.setup['bundle'] or self.setup['skipindep']))):
continue
- tl = [t for t in self.tools if t.handlesEntry(cfile) \
- and t.canVerify(cfile)]
+ tl = [t for t in self.tools
+ if t.handlesEntry(cfile) and t.canVerify(cfile)]
if tl:
if self.setup['interactive'] and not \
- promptFilter("Install %s: %s? (y/N):", [cfile]):
+ self.promptFilter("Install %s: %s? (y/N):", [cfile]):
self.whitelist.remove(cfile)
continue
try:
@@ -262,22 +286,33 @@ class Frame:
return
# Here is where most of the work goes
# first perform bundle filtering
+ all_bundle_names = [b.get('name')
+ for b in self.config.findall('./Bundle')]
+ bundles = self.config.getchildren()
if self.setup['bundle']:
- all_bundle_names = [b.get('name') for b in
- self.config.findall('./Bundle')]
# warn if non-existent bundle given
for bundle in self.setup['bundle']:
if bundle not in all_bundle_names:
self.logger.info("Warning: Bundle %s not found" % bundle)
- bundles = [b for b in self.config.findall('./Bundle')
- if b.get('name') in self.setup['bundle']]
- self.whitelist = [e for e in self.whitelist
- if True in [e in b for b in bundles]]
+ bundles = filter(lambda b: b.get('name') in self.setup['bundle'],
+ bundles)
elif self.setup['indep']:
- bundles = [nb for nb in self.config.getchildren()
- if nb.tag != 'Bundle']
- else:
- bundles = self.config.getchildren()
+ bundles = filter(lambda b: b.tag != 'Bundle', bundles)
+ if self.setup['skipbundle']:
+ # warn if non-existent bundle given
+ if not self.setup['bundle_quick']:
+ for bundle in self.setup['skipbundle']:
+ if bundle not in all_bundle_names:
+ self.logger.info("Warning: Bundle %s not found" %
+ bundle)
+ bundles = filter(lambda b: \
+ b.get('name') not in self.setup['skipbundle'],
+ bundles)
+ if self.setup['skipindep']:
+ bundles = filter(lambda b: b.tag == 'Bundle', bundles)
+
+ self.whitelist = [e for e in self.whitelist
+ if True in [e in b for b in bundles]]
# first process prereq actions
for bundle in bundles[:]:
@@ -289,7 +324,7 @@ class Frame:
(bmodified or a.get('when') == 'always'))]
# now we process all "always actions"
if self.setup['interactive']:
- promptFilter(prompt, actions)
+ self.promptFilter(prompt, actions)
self.DispatchInstallCalls(actions)
# need to test to fail entries in whitelist
@@ -307,8 +342,8 @@ class Frame:
[self.whitelist.remove(ent) for ent in b_to_remv]
if self.setup['interactive']:
- self.whitelist = promptFilter(prompt, self.whitelist)
- self.removal = promptFilter(rprompt, self.removal)
+ self.whitelist = self.promptFilter(prompt, self.whitelist)
+ self.removal = self.promptFilter(rprompt, self.removal)
for entry in candidates:
if entry not in self.whitelist:
@@ -337,7 +372,6 @@ class Frame:
if mbundles:
self.logger.info("The Following Bundles have been modified:")
self.logger.info([mbun.get('name') for mbun in mbundles])
- self.logger.info("")
tbm = [(t, b) for t in self.tools for b in mbundles]
for tool, bundle in tbm:
try:
@@ -380,19 +414,33 @@ class Frame:
def CondDisplayState(self, phase):
"""Conditionally print tracing information."""
- self.logger.info('\nPhase: %s' % phase)
- self.logger.info('Correct entries:\t%d' % list(self.states.values()).count(True))
- self.logger.info('Incorrect entries:\t%d' % list(self.states.values()).count(False))
+ self.logger.info('Phase: %s' % phase)
+ self.logger.info('Correct entries: %d' %
+ list(self.states.values()).count(True))
+ self.logger.info('Incorrect entries: %d' %
+ list(self.states.values()).count(False))
if phase == 'final' and list(self.states.values()).count(False):
- self.logger.info(["%s:%s" % (entry.tag, entry.get('name')) for \
- entry in self.states if not self.states[entry]])
- self.logger.info('Total managed entries:\t%d' % len(list(self.states.values())))
- self.logger.info('Unmanaged entries:\t%d' % len(self.extra))
+ for entry in self.states.keys():
+ if not self.states[entry]:
+ etype = entry.get('type')
+ if etype:
+ self.logger.info( "%s:%s:%s" % (entry.tag, etype,
+ entry.get('name')))
+ else:
+ self.logger.info(" %s:%s" % (entry.tag,
+ entry.get('name')))
+ self.logger.info('Total managed entries: %d' %
+ len(list(self.states.values())))
+ self.logger.info('Unmanaged entries: %d' % len(self.extra))
if phase == 'final' and self.setup['extra']:
- self.logger.info(["%s:%s" % (entry.tag, entry.get('name')) \
- for entry in self.extra])
-
- self.logger.info("")
+ for entry in self.extra:
+ etype = entry.get('type')
+ if etype:
+ self.logger.info( "%s:%s:%s" % (entry.tag, etype,
+ entry.get('name')))
+ else:
+ self.logger.info(" %s:%s" % (entry.tag,
+ entry.get('name')))
if ((list(self.states.values()).count(False) == 0) and not self.extra):
self.logger.info('All entries correct.')
@@ -428,7 +476,8 @@ class Frame:
total=str(len(self.states)),
version='2.0',
revision=self.config.get('revision', '-1'))
- good = len([key for key, val in list(self.states.items()) if val])
+ good_entries = [key for key, val in list(self.states.items()) if val]
+ good = len(good_entries)
stats.set('good', str(good))
if len([key for key, val in list(self.states.items()) if not val]) == 0:
stats.set('state', 'clean')
@@ -437,6 +486,7 @@ class Frame:
# List bad elements of the configuration
for (data, ename) in [(self.modified, 'Modified'), (self.extra, "Extra"), \
+ (good_entries, "Good"),
([entry for entry in self.states if not \
self.states[entry]], "Bad")]:
container = Bcfg2.Client.XML.SubElement(stats, ename)