diff options
Diffstat (limited to 'src/sbin/bcfg2-info')
-rwxr-xr-x | src/sbin/bcfg2-info | 225 |
1 files changed, 126 insertions, 99 deletions
diff --git a/src/sbin/bcfg2-info b/src/sbin/bcfg2-info index 8598a58eb..7cc361a1c 100755 --- a/src/sbin/bcfg2-info +++ b/src/sbin/bcfg2-info @@ -10,6 +10,7 @@ import fnmatch import logging import tempfile import lxml.etree +import traceback from code import InteractiveConsole try: @@ -26,9 +27,14 @@ import Bcfg2.Logger import Bcfg2.Options import Bcfg2.Server.Core import Bcfg2.Server.Plugins.Metadata -import Bcfg2.Server.Plugins.SGenshi import Bcfg2.Server.Plugin +try: + from Bcfg2.Server.Plugins.Bundler import BundleTemplateFile + has_genshi = True +except ImportError: + has_genshi = False + logger = logging.getLogger('bcfg2-info') USAGE = """Commands: build <hostname> <filename> - Build config for hostname, writing to filename @@ -96,7 +102,7 @@ def getClientList(hostglobs): """ given a host glob, get a list of clients that match it """ # special cases to speed things up: if '*' in hostglobs: - return list(self.metadata.clients.keys()) + return self.metadata.clients has_wildcards = False for glob in hostglobs: # check if any wildcard characters are in the string @@ -107,7 +113,7 @@ def getClientList(hostglobs): return hostglobs rv = set() - clist = set(self.metadata.clients.keys()) + clist = set(self.metadata.clients) for glob in hostglobs: for client in clist: if fnmatch.fnmatch(client, glob): @@ -131,20 +137,50 @@ def displayTrace(trace, num=80, sort=('time', 'calls')): stats.sort_stats('cumulative', 'calls', 'time') stats.print_stats(200) -class infoCore(cmd.Cmd, Bcfg2.Server.Core.Core): +def load_interpreters(): + interpreters = dict(python=lambda v: InteractiveConsole(v).interact()) + best = "python" + try: + import bpython.cli + interpreters["bpython"] = lambda v: bpython.cli.main(args=[], locals_=v) + best = "bpython" + except ImportError: + pass + + try: + # whether ipython is actually better than bpython is + # up for debate, but this is the behavior that existed + # before --interpreter was added, so we call IPython + # better + import IPython + if hasattr(IPython, "Shell"): + interpreters["ipython"] = lambda v: \ + IPython.Shell.IPShell(argv=[], user_ns=v).mainloop() + best = "ipython" + elif hasattr(IPython, "embed"): + interpreters["ipython"] = lambda v: IPython.embed(user_ns=v) + best = "ipython" + else: + print("Unknown IPython API version") + except ImportError: + pass + + interpreters['best'] = interpreters[best] + return interpreters + + +class infoCore(cmd.Cmd, Bcfg2.Server.Core.BaseCore): """Main class for bcfg2-info.""" def __init__(self, repo, plgs, passwd, encoding, event_debug, filemonitor='default', setup=None): cmd.Cmd.__init__(self) try: - Bcfg2.Server.Core.Core.__init__(self, repo, plgs, passwd, - encoding, filemonitor=filemonitor, - setup=setup) + Bcfg2.Server.Core.BaseCore.__init__(self, setup=setup) if event_debug: self.fam.debug = True except Bcfg2.Server.Core.CoreInitError: msg = sys.exc_info()[1] - print("Core load failed because %s" % msg) + print("Core load failed: %s" % msg) raise SystemExit(1) self.prompt = '> ' self.cont = True @@ -185,24 +221,21 @@ class infoCore(cmd.Cmd, Bcfg2.Server.Core.Core): spath = opt[1] elif opt[0] == '-n': interactive = False - sh = InteractiveConsole(locals()) if scriptmode: + sh = InteractiveConsole(locals()) for command in [c.strip() for c in open(spath).readlines()]: if command: sh.push(command) if interactive: - print("Dropping to python interpreter; press ^D to resume") - try: - import IPython - if hasattr(IPython, "Shell"): - shell = IPython.Shell.IPShell(argv=[], user_ns=locals()) - shell.mainloop() - elif hasattr(IPython, "embed"): - IPython.embed(user_ns=locals()) - else: - raise ImportError - except ImportError: - sh.interact() + interpreters = load_interpreters() + if setup['interpreter'] in interpreters: + print("Dropping to %s interpreter; press ^D to resume" % + setup['interpreter']) + interpreters[setup['interpreter']](locals()) + else: + logger.error("Invalid interpreter %s" % setup['interpreter']) + logger.error("Valid interpreters are: %s" % + ", ".join(interpeters.keys())) def do_quit(self, _): """ @@ -295,7 +328,7 @@ class infoCore(cmd.Cmd, Bcfg2.Server.Core.Core): if len(alist) > 1: clients = getClientList(alist[1:]) else: - clients = list(self.metadata.clients.keys()) + clients = self.metadata.clients for client in clients: self.do_build("%s %s" % (client, os.path.join(destdir, client + ".xml"))) @@ -327,7 +360,7 @@ class infoCore(cmd.Cmd, Bcfg2.Server.Core.Core): if len(args) > 2: clients = getClientList(args[1:]) else: - clients = list(self.metadata.clients.keys()) + clients = self.metadata.clients if altsrc: args = "--altsrc %s -f %%s %%s %%s" % altsrc else: @@ -362,8 +395,8 @@ class infoCore(cmd.Cmd, Bcfg2.Server.Core.Core): try: metadata = self.build_metadata(client) self.Bind(entry, metadata) - data = lxml.etree.tostring(entry, encoding="UTF-8", - xml_declaration=True) + data = lxml.etree.tostring(entry, + xml_declaration=False).decode('UTF-8') if outfile: open(outfile, 'w').write(data) else: @@ -373,7 +406,8 @@ class infoCore(cmd.Cmd, Bcfg2.Server.Core.Core): print("Could not write to %s: %s" % (outfile, err)) print(data) except Exception: - print("Failed to build entry %s for host %s" % (fname, client)) + print("Failed to build entry %s for host %s: %s" % + (fname, client, traceback.format_exc().splitlines()[-1])) raise def do_buildbundle(self, args): @@ -384,8 +418,9 @@ class infoCore(cmd.Cmd, Bcfg2.Server.Core.Core): metadata = self.build_metadata(client) if bname in self.plugins['Bundler'].entries: bundle = self.plugins['Bundler'].entries[bname] - if isinstance(bundle, - Bcfg2.Server.Plugins.SGenshi.SGenshiTemplateFile): + if (has_genshi and + isinstance(bundle, + BundleTemplateFile)): stream = bundle.template.generate(metadata=metadata) print(stream.render("xml")) else: @@ -413,10 +448,11 @@ class infoCore(cmd.Cmd, Bcfg2.Server.Core.Core): def do_clients(self, _): """Print out client info.""" data = [('Client', 'Profile')] - clist = list(self.metadata.clients.keys()) + clist = self.metadata.clients clist.sort() for client in clist: - data.append((client, self.metadata.clients[client])) + imd = self.metadata.get_initial_metadata(client) + data.append((client, imd.profile)) printTabular(data) def do_config(self, _): @@ -466,22 +502,18 @@ class infoCore(cmd.Cmd, Bcfg2.Server.Core.Core): def do_groups(self, _): """Print out group info.""" - data = [("Groups", "Profile", "Category", "Contains")] + # FIXME: Contains doesn't work. Not sure what it was used for + #data = [("Groups", "Profile", "Category", "Contains")] + data = [("Groups", "Profile", "Category")] grouplist = list(self.metadata.groups.keys()) grouplist.sort() for group in grouplist: - if group in self.metadata.profiles: + if self.metadata.groups[group].is_profile: prof = 'yes' else: prof = 'no' - if group in self.metadata.categories: - cat = self.metadata.categories[group] - else: - cat = '' - gdata = [grp for grp in self.metadata.groups[group][1]] - if group in gdata: - gdata.remove(group) - data.append((group, prof, cat, ','.join(gdata))) + cat = self.metadata.groups[group].category + data.append((group, prof, cat)) printTabular(data) def do_showclient(self, args): @@ -496,21 +528,34 @@ class infoCore(cmd.Cmd, Bcfg2.Server.Core.Core): except: print("Client %s not defined" % client) continue - print("Hostname:\t%s" % client_meta.hostname) - print("Profile:\t%s" % client_meta.profile) - print("Groups:\t\t%s" % list(client_meta.groups)[0]) - for grp in list(client_meta.groups)[1:]: - print("\t\t%s" % grp) + fmt = "%-10s %s" + print(fmt % ("Hostname:", client_meta.hostname)) + print(fmt % ("Profile:", client_meta.profile)) + + group_fmt = "%-10s %-30s %s" + header = False + for group in list(client_meta.groups): + category = "" + for cat, grp in client_meta.categories.items(): + if grp == group: + category = "Category: %s" % cat + break + if not header: + print(group_fmt % ("Groups:", group, category)) + header = True + else: + print(group_fmt % ("", group, category)) + if client_meta.bundles: - print("Bundles:\t%s" % list(client_meta.bundles)[0]) + print(fmt % ("Bundles:", list(client_meta.bundles)[0])) for bnd in list(client_meta.bundles)[1:]: - print("\t\t%s" % bnd) + print(fmt % ("", bnd)) if client_meta.connectors: print("Connector data") print("=" * 80) for conn in client_meta.connectors: if getattr(client_meta, conn): - print("%s:\t%s" % (conn, getattr(client_meta, conn))) + print(fmt % (conn + ":", getattr(client_meta, conn))) print("=" * 80) def do_mappings(self, args): @@ -568,6 +613,9 @@ class infoCore(cmd.Cmd, Bcfg2.Server.Core.Core): print("Usage: packageresolve <hostname> <package> [<package>...]") return + if 'Packages' not in self.plugins: + print("Packages plugin not enabled") + return hostname = arglist[0] initial = arglist[1:] metadata = self.build_metadata(hostname) @@ -585,42 +633,28 @@ class infoCore(cmd.Cmd, Bcfg2.Server.Core.Core): print(" %s" % "\n ".join(unknown)) def do_packagesources(self, args): + if not args: + print("Usage: packagesources <hostname>") + return + if 'Packages' not in self.plugins: + print("Packages plugin not enabled") + return try: metadata = self.build_metadata(args) except Bcfg2.Server.Plugins.Metadata.MetadataConsistencyError: print("Unable to build metadata for host %s" % args) return collection = self.plugins['Packages']._get_collection(metadata) - for source in collection.sources: - # get_urls() loads url_map as a side-effect - source.get_urls() - for url_map in source.url_map: - for arch in url_map['arches']: - # make sure client is in all the proper arch groups - if arch not in metadata.groups: - continue - reponame = source.get_repo_name(url_map) - print("Name: %s" % reponame) - print(" Type: %s" % source.ptype) - if url_map['url'] != '': - print(" URL: %s" % url_map['url']) - elif url_map['rawurl'] != '': - print(" RAWURL: %s" % url_map['rawurl']) - if source.gpgkeys: - print(" GPG Key(s): %s" % ", ".join(source.gpgkeys)) - else: - print(" GPG Key(s): None") - if len(source.blacklist): - print(" Blacklist: %s" % ", ".join(source.blacklist)) - if len(source.whitelist): - print(" Whitelist: %s" % ", ".join(source.whitelist)) - print("") + print(collection.sourcelist()) def do_profile(self, arg): """.""" if not have_profile: print("Profiling functionality not available.") return + if len(arg) == 0: + print("Usage: profile <command> <args>") + return tracefname = tempfile.mktemp() p = profile.Profile() p.runcall(self.onecmd, arg) @@ -635,34 +669,27 @@ class infoCore(cmd.Cmd, Bcfg2.Server.Core.Core): self.do_loop() if __name__ == '__main__': - Bcfg2.Logger.setup_logging('bcfg2-info', to_syslog=False) - optinfo = { - 'configfile': Bcfg2.Options.CFILE, - 'help': Bcfg2.Options.HELP, - 'event debug': Bcfg2.Options.DEBUG, - 'profile': Bcfg2.Options.CORE_PROFILE, - 'encoding': Bcfg2.Options.ENCODING, - # Server options - 'repo': Bcfg2.Options.SERVER_REPOSITORY, - 'plugins': Bcfg2.Options.SERVER_PLUGINS, - 'password': Bcfg2.Options.SERVER_PASSWORD, - 'mconnect': Bcfg2.Options.SERVER_MCONNECT, - 'filemonitor': Bcfg2.Options.SERVER_FILEMONITOR, - 'location': Bcfg2.Options.SERVER_LOCATION, - 'static': Bcfg2.Options.SERVER_STATIC, - 'key': Bcfg2.Options.SERVER_KEY, - 'cert': Bcfg2.Options.SERVER_CERT, - 'ca': Bcfg2.Options.SERVER_CA, - 'password': Bcfg2.Options.SERVER_PASSWORD, - 'protocol': Bcfg2.Options.SERVER_PROTOCOL, - # More options - 'logging': Bcfg2.Options.LOGGING_FILE_PATH - } + optinfo = dict(profile=Bcfg2.Options.CORE_PROFILE, + mconnect=Bcfg2.Options.SERVER_MCONNECT, + interactive=Bcfg2.Options.INTERACTIVE, + interpreter=Bcfg2.Options.INTERPRETER) + optinfo.update(Bcfg2.Options.CLI_COMMON_OPTIONS) + optinfo.update(Bcfg2.Options.SERVER_COMMON_OPTIONS) setup = Bcfg2.Options.OptionParser(optinfo) - setup.hm = "Usage:\n %s\n%s" % (setup.buildHelpMessage(), - USAGE) + setup.hm = "\n".join([" bcfg2-info [options] [command <command args>]", + "Options:", + setup.buildHelpMessage(), + USAGE]) setup.parse(sys.argv[1:]) + if setup['debug']: + level = logging.DEBUG + elif setup['verbose']: + level = logging.INFO + else: + level = logging.WARNING + Bcfg2.Logger.setup_logging('bcfg2-info', to_syslog=False, + level=level) if setup['args'] and setup['args'][0] == 'help': print(setup.hm) sys.exit(0) @@ -670,14 +697,14 @@ if __name__ == '__main__': prof = profile.Profile() loop = prof.runcall(infoCore, setup['repo'], setup['plugins'], setup['password'], setup['encoding'], - setup['event debug'], setup['filemonitor'], + setup['debug'], setup['filemonitor'], setup) displayTrace(prof) else: if setup['profile']: print("Profiling functionality not available.") loop = infoCore(setup['repo'], setup['plugins'], setup['password'], - setup['encoding'], setup['event debug'], + setup['encoding'], setup['debug'], setup['filemonitor'], setup) loop.Run(setup['args']) |