summaryrefslogtreecommitdiffstats
path: root/src/sbin/bcfg2-info
diff options
context:
space:
mode:
Diffstat (limited to 'src/sbin/bcfg2-info')
-rwxr-xr-xsrc/sbin/bcfg2-info225
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'])