diff options
Diffstat (limited to 'src/lib/Bcfg2/Client/Frame.py')
-rw-r--r-- | src/lib/Bcfg2/Client/Frame.py | 210 |
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) |