summaryrefslogtreecommitdiffstats
path: root/src/sbin
diff options
context:
space:
mode:
authorChris St. Pierre <chris.a.st.pierre@gmail.com>2013-06-27 10:29:12 -0400
committerChris St. Pierre <chris.a.st.pierre@gmail.com>2013-06-27 10:41:29 -0400
commit27f747b319f65ca9b01fddcbb0a73176dedf9541 (patch)
tree49992c6f904912307d850c7af094cc3e10665c28 /src/sbin
parent2d1f13115150af2dd9b74e1a928f40fc19cf0dd1 (diff)
downloadbcfg2-27f747b319f65ca9b01fddcbb0a73176dedf9541.tar.gz
bcfg2-27f747b319f65ca9b01fddcbb0a73176dedf9541.tar.bz2
bcfg2-27f747b319f65ca9b01fddcbb0a73176dedf9541.zip
Options: migrated bcfg2-info to new parser
Diffstat (limited to 'src/sbin')
-rwxr-xr-xsrc/sbin/bcfg2-info790
1 files changed, 2 insertions, 788 deletions
diff --git a/src/sbin/bcfg2-info b/src/sbin/bcfg2-info
index 1fd9bc067..adfa96852 100755
--- a/src/sbin/bcfg2-info
+++ b/src/sbin/bcfg2-info
@@ -1,794 +1,8 @@
#!/usr/bin/env python
"""This tool loads the Bcfg2 core into an interactive debugger."""
-import os
-import re
import sys
-import cmd
-import getopt
-import fnmatch
-import logging
-import lxml.etree
-import traceback
-from code import InteractiveConsole
-import Bcfg2.Logger
-import Bcfg2.Options
-import Bcfg2.Server.Core
-import Bcfg2.Server.Plugin
-import Bcfg2.Client.Tools.POSIX
-
-try:
- try:
- import cProfile as profile
- except ImportError:
- import profile
- import pstats
- HAS_PROFILE = True
-except ImportError:
- HAS_PROFILE = False
-
-
-class MockLog(object):
- """ Fake logger that just discards all messages in order to mask
- errors from builddir being unable to chown files it creates """
- def error(self, *args, **kwargs):
- """ discard error messages """
- pass
-
- def warning(self, *args, **kwargs):
- """ discard warning messages """
- pass
-
- def info(self, *args, **kwargs):
- """ discard info messages """
- pass
-
- def debug(self, *args, **kwargs):
- """ discard debug messages """
- pass
-
-
-class FileNotBuilt(Exception):
- """Thrown when File entry contains no content."""
- def __init__(self, value):
- Exception.__init__(self)
- self.value = value
-
- def __str__(self):
- return repr(self.value)
-
-
-def print_tabular(rows):
- """Print data in tabular format."""
- cmax = tuple([max([len(str(row[index])) for row in rows]) + 1
- for index in range(len(rows[0]))])
- fstring = (" %%-%ss |" * len(cmax)) % cmax
- fstring = ('|'.join([" %%-%ss "] * len(cmax))) % cmax
- print(fstring % rows[0])
- print((sum(cmax) + (len(cmax) * 2) + (len(cmax) - 1)) * '=')
- for row in rows[1:]:
- print(fstring % row)
-
-
-def display_trace(trace):
- """ display statistics from a profile trace """
- stats = pstats.Stats(trace)
- stats.sort_stats('cumulative', 'calls', 'time')
- stats.print_stats(200)
-
-
-def load_interpreters():
- """ Load a dict of available Python 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
- # pylint: disable=E1101
- 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")
- # pylint: enable=E1101
- 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):
- cmd.Cmd.__init__(self)
- Bcfg2.Server.Core.BaseCore.__init__(self)
- self.prompt = '> '
- self.cont = True
-
- def _get_client_list(self, hostglobs):
- """ given a host glob, get a list of clients that match it """
- # special cases to speed things up:
- if '*' in hostglobs:
- return self.metadata.clients
- has_wildcards = False
- for glob in hostglobs:
- # check if any wildcard characters are in the string
- if set('*?[]') & set(glob):
- has_wildcards = True
- break
- if not has_wildcards:
- return hostglobs
-
- rv = set()
- clist = set(self.metadata.clients)
- for glob in hostglobs:
- for client in clist:
- if fnmatch.fnmatch(client, glob):
- rv.update(client)
- clist.difference_update(rv)
- return list(rv)
-
- def _get_usage(self, func):
- """ get the short usage message for a given function """
- return "Usage: " + re.sub(r'\s+', ' ', func.__doc__).split(" - ", 1)[0]
-
- def do_loop(self):
- """Looping."""
- self.cont = True
- while self.cont:
- try:
- self.cmdloop('Welcome to bcfg2-info\n'
- 'Type "help" for more information')
- except SystemExit:
- raise
- except Bcfg2.Server.Plugin.PluginExecutionError:
- continue
- except KeyboardInterrupt:
- print("Ctrl-C pressed exiting...")
- self.do_exit([])
- except:
- self.logger.error("Command failure", exc_info=1)
-
- def do_debug(self, args):
- """ debug [-n] [-f <command list>] - Shell out to native
- python interpreter """
- try:
- opts, _ = getopt.getopt(args.split(), 'nf:')
- except getopt.GetoptError:
- print(str(sys.exc_info()[1]))
- print(self._get_usage(self.do_debug))
- return
- self.cont = False
- scriptmode = False
- interactive = True
- for opt in opts:
- if opt[0] == '-f':
- scriptmode = True
- spath = opt[1]
- elif opt[0] == '-n':
- interactive = False
- if scriptmode:
- console = InteractiveConsole(locals())
- for command in [c.strip() for c in open(spath).readlines()]:
- if command:
- console.push(command)
- if interactive:
- interpreters = load_interpreters()
- if self.setup['interpreter'] in interpreters:
- print("Dropping to %s interpreter; press ^D to resume" %
- self.setup['interpreter'])
- interpreters[self.setup['interpreter']](locals())
- else:
- self.logger.error("Invalid interpreter %s" %
- self.setup['interpreter'])
- self.logger.error("Valid interpreters are: %s" %
- ", ".join(interpreters.keys()))
-
- def do_quit(self, _):
- """ quit|exit - Exit program """
- self.shutdown()
- os._exit(0) # pylint: disable=W0212
-
- do_EOF = do_quit
- do_exit = do_quit
-
- def do_help(self, _):
- """ help - Print this list of available commands """
- print(USAGE)
-
- def do_update(self, _):
- """ update - Process pending filesystem events"""
- self.fam.handle_events_in_interval(0.1)
-
- def do_build(self, args):
- """ build [-f] <hostname> <filename> - Build config for
- hostname, writing to filename"""
- alist = args.split()
- path_force = False
- for arg in alist:
- if arg == '-f':
- alist.remove('-f')
- path_force = True
- if len(alist) == 2:
- client, ofile = alist
- if not ofile.startswith('/tmp') and not path_force:
- print("Refusing to write files outside of /tmp without -f "
- "option")
- return
- try:
- lxml.etree.ElementTree(self.BuildConfiguration(client)).write(
- ofile,
- encoding='UTF-8', xml_declaration=True,
- pretty_print=True)
- except IOError:
- err = sys.exc_info()[1]
- print("Failed to write File %s: %s" % (ofile, err))
- else:
- print(self._get_usage(self.do_build))
-
- def help_builddir(self):
- """Display help for builddir command."""
- print("""Usage: builddir [-f] <hostname> <output dir>
-
-Generates a config for client <hostname> and writes the
-individual configuration files out separately in a tree
-under <output dir>. The <output dir> directory must be
-rooted under /tmp unless the -f argument is provided, in
-which case it can be located anywhere.
-
-NOTE: Currently only handles file entries and writes
-all content with the default owner and permissions. These
-could be much more permissive than would be created by the
-Bcfg2 client itself.""")
-
- def do_builddir(self, args):
- """ builddir [-f] <hostname> <dirname> - Build config for
- hostname, writing separate files to dirname"""
- alist = args.split()
- path_force = False
- if '-f' in args:
- alist.remove('-f')
- path_force = True
- if len(alist) == 2:
- client, odir = alist
- if not odir.startswith('/tmp') and not path_force:
- print("Refusing to write files outside of /tmp without -f "
- "option")
- return
- client_config = self.BuildConfiguration(client)
- if client_config.tag == 'error':
- print("Building client configuration failed.")
- return
-
- for struct in client_config:
- for entry in struct:
- if entry.tag == 'Path':
- entry.set('name', odir + '/' + entry.get('name'))
-
- posix = Bcfg2.Client.Tools.POSIX.POSIX(MockLog(),
- self.setup,
- client_config)
- states = posix.Inventory()
- posix.Install(list(states.keys()))
- else:
- print('Error: Incorrect number of parameters.')
- self.help_builddir()
-
- def do_buildall(self, args):
- """ buildall <directory> [<hostnames*>] - Build configs for
- all clients in directory """
- alist = args.split()
- if len(alist) < 1:
- print(self._get_usage(self.do_buildall))
- return
-
- destdir = alist[0]
- try:
- os.mkdir(destdir)
- except OSError:
- err = sys.exc_info()[1]
- if err.errno != 17:
- print("Could not create %s: %s" % (destdir, err))
- if len(alist) > 1:
- clients = self._get_client_list(alist[1:])
- else:
- clients = self.metadata.clients
- for client in clients:
- self.do_build("%s %s" % (client, os.path.join(destdir,
- client + ".xml")))
-
- def do_buildallfile(self, args):
- """ buildallfile <directory> <filename> [<hostnames*>] - Build
- config file for all clients in directory """
- try:
- opts, args = getopt.gnu_getopt(args.split(), '', ['altsrc='])
- except getopt.GetoptError:
- print(str(sys.exc_info()[1]))
- print(self._get_usage(self.do_buildallfile))
- return
- altsrc = None
- for opt in opts:
- if opt[0] == '--altsrc':
- altsrc = opt[1]
- if len(args) < 2:
- print(self._get_usage(self.do_buildallfile))
- return
-
- destdir = args[0]
- filename = args[1]
- try:
- os.mkdir(destdir)
- except OSError:
- err = sys.exc_info()[1]
- if err.errno != 17:
- print("Could not create %s: %s" % (destdir, err))
- if len(args) > 2:
- clients = self._get_client_list(args[1:])
- else:
- clients = self.metadata.clients
- if altsrc:
- args = "--altsrc %s -f %%s %%s %%s" % altsrc
- else:
- args = "-f %s %s %s"
- for client in clients:
- self.do_buildfile(args % (os.path.join(destdir, client),
- filename, client))
-
- def do_buildfile(self, args):
- """ buildfile [-f <outfile>] [--altsrc=<altsrc>] <filename>
- <hostname> - Build config file for hostname (not written to
- disk)"""
- try:
- opts, alist = getopt.gnu_getopt(args.split(), 'f:', ['altsrc='])
- except getopt.GetoptError:
- print(str(sys.exc_info()[1]))
- print(self.do_buildfile.__doc__)
- return
- altsrc = None
- outfile = None
- for opt in opts:
- if opt[0] == '--altsrc':
- altsrc = opt[1]
- elif opt[0] == '-f':
- outfile = opt[1]
- if len(alist) != 2:
- print(self.do_buildfile.__doc__)
- return
-
- fname, client = alist
- entry = lxml.etree.Element('Path', type='file', name=fname)
- if altsrc:
- entry.set("altsrc", altsrc)
- try:
- metadata = self.build_metadata(client)
- self.Bind(entry, metadata)
- data = lxml.etree.tostring(entry,
- xml_declaration=False).decode('UTF-8')
- except Exception:
- print("Failed to build entry %s for host %s: %s" %
- (fname, client, traceback.format_exc().splitlines()[-1]))
- raise
- try:
- if outfile:
- open(outfile, 'w').write(data)
- else:
- print(data)
- except IOError:
- err = sys.exc_info()[1]
- print("Could not write to %s: %s" % (outfile, err))
- print(data)
-
- def do_buildbundle(self, args):
- """ buildbundle <bundle> <hostname> - Render a templated
- bundle for hostname (not written to disk) """
- if len(args.split()) != 2:
- print(self._get_usage(self.do_buildbundle))
- return 1
-
- bname, client = args.split()
- try:
- metadata = self.build_metadata(client)
- bundle = self.plugins['Bundler'].entries[bname]
- print(lxml.etree.tostring(bundle.get_xml_value(metadata),
- xml_declaration=False,
- pretty_print=True).decode('UTF-8'))
- except KeyError:
- print("No such bundle %s" % bname)
- except: # pylint: disable=W0702
- err = sys.exc_info()[1]
- print("Failed to render bundle %s for host %s: %s" % (bname,
- client,
- err))
-
- def do_automatch(self, args):
- """ automatch [-f] <propertyfile> <hostname> - Perform automatch on
- a Properties file """
- alist = args.split()
- force = False
- for arg in alist:
- if arg == '-f':
- alist.remove('-f')
- force = True
- if len(alist) != 2:
- print(self._get_usage(self.do_automatch))
- return
-
- if 'Properties' not in self.plugins:
- print("Properties plugin not enabled")
- return
-
- pname, client = alist
- automatch = self.setup.cfp.getboolean("properties", "automatch",
- default=False)
- pfile = self.plugins['Properties'].store.entries[pname]
- if (not force and
- not automatch and
- pfile.xdata.get("automatch", "false").lower() != "true"):
- print("Automatch not enabled on %s" % pname)
- else:
- metadata = self.build_metadata(client)
- print(lxml.etree.tostring(pfile.XMLMatch(metadata),
- xml_declaration=False,
- pretty_print=True).decode('UTF-8'))
-
- def do_bundles(self, _):
- """ bundles - Print out group/bundle info """
- data = [('Group', 'Bundles')]
- groups = list(self.metadata.groups.keys())
- groups.sort()
- for group in groups:
- data.append((group,
- ','.join(self.metadata.groups[group][0])))
- print_tabular(data)
-
- def do_clients(self, _):
- """ clients - Print out client/profile info """
- data = [('Client', 'Profile')]
- for client in sorted(self.metadata.list_clients()):
- imd = self.metadata.get_initial_metadata(client)
- data.append((client, imd.profile))
- print_tabular(data)
-
- def do_config(self, _):
- """ config - Print out the current configuration of Bcfg2"""
- output = [
- ('Description', 'Value'),
- ('Path Bcfg2 repository', self.setup['repo']),
- ('Plugins', self.setup['plugins']),
- ('Password', self.setup['password']),
- ('Filemonitor', self.setup['filemonitor']),
- ('Server address', self.setup['location']),
- ('Path to key', self.setup['key']),
- ('Path to SSL certificate', self.setup['cert']),
- ('Path to SSL CA certificate', self.setup['ca']),
- ('Protocol', self.setup['protocol']),
- ('Logging', self.setup['logging'])]
- print_tabular(output)
-
- def do_probes(self, args):
- """ probes [-p] <hostname> - Get probe list for the given
- host, in XML (the default) or human-readable pretty (with -p)
- format"""
- alist = args.split()
- pretty = False
- if '-p' in alist:
- pretty = True
- alist.remove('-p')
- if len(alist) != 1:
- print(self._get_usage(self.do_probes))
- return
- hostname = alist[0]
- if pretty:
- probes = []
- else:
- probes = lxml.etree.Element('probes')
- metadata = self.build_metadata(hostname)
- for plugin in self.plugins_by_type(Bcfg2.Server.Plugin.Probing):
- for probe in plugin.GetProbes(metadata):
- probes.append(probe)
- if pretty:
- for probe in probes:
- pname = probe.get("name")
- print("=" * (len(pname) + 2))
- print(" %s" % pname)
- print("=" * (len(pname) + 2))
- print("")
- print(probe.text)
- print("")
- else:
- print(lxml.etree.tostring(probes,
- xml_declaration=False,
- pretty_print=True).decode('UTF-8'))
-
- def do_showentries(self, args):
- """ showentries <hostname> <type> - Show abstract
- configuration entries for a given host """
- arglen = len(args.split())
- if arglen not in [1, 2]:
- print(self._get_usage(self.do_showentries))
- return
- client = args.split()[0]
- try:
- meta = self.build_metadata(client)
- except Bcfg2.Server.Plugin.MetadataConsistencyError:
- print("Unable to find metadata for host %s" % client)
- return
- structures = self.GetStructures(meta)
- output = [('entrytype', 'name')]
- if arglen == 1:
- for item in structures:
- for child in item.getchildren():
- output.append((child.tag, child.get('name')))
- if arglen == 2:
- etype = args.split()[1]
- for item in structures:
- for child in item.getchildren():
- if child.tag in [etype, "Bound%s" % etype]:
- output.append((child.tag, child.get('name')))
- print_tabular(output)
-
- def do_groups(self, _):
- """ groups - Print out group info """
- data = [("Groups", "Profile", "Category")]
- grouplist = list(self.metadata.groups.keys())
- grouplist.sort()
- for group in grouplist:
- if self.metadata.groups[group].is_profile:
- prof = 'yes'
- else:
- prof = 'no'
- cat = self.metadata.groups[group].category
- data.append((group, prof, cat))
- print_tabular(data)
-
- def do_showclient(self, args):
- """ showclient <client> [<client> ...] - Show metadata for the
- given hosts """
- if not len(args):
- print(self._get_usage(self.do_showclient))
- return
- for client in args.split():
- try:
- client_meta = self.build_metadata(client)
- except Bcfg2.Server.Plugin.MetadataConsistencyError:
- print("Client %s not defined" % client)
- continue
- 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(fmt % ("Bundles:", list(client_meta.bundles)[0]))
- for bnd in list(client_meta.bundles)[1:]:
- print(fmt % ("", bnd))
- if client_meta.connectors:
- print("Connector data")
- print("=" * 80)
- for conn in client_meta.connectors:
- if getattr(client_meta, conn):
- print(fmt % (conn + ":", getattr(client_meta, conn)))
- print("=" * 80)
-
- def do_mappings(self, args):
- """ mappings <type*> <name*> - Print generator mappings for
- optional type and name """
- # Dump all mappings unless type specified
- data = [('Plugin', 'Type', 'Name')]
- arglen = len(args.split())
- for generator in self.plugins_by_type(Bcfg2.Server.Plugin.Generator):
- if arglen == 0:
- etypes = list(generator.Entries.keys())
- else:
- etypes = [args.split()[0]]
- if arglen == 2:
- interested = [(etype, [args.split()[1]])
- for etype in etypes]
- else:
- interested = [(etype, generator.Entries[etype])
- for etype in etypes
- if etype in generator.Entries]
- for etype, names in interested:
- for name in [name for name in names if name in
- generator.Entries.get(etype, {})]:
- data.append((generator.name, etype, name))
- print_tabular(data)
-
- def do_event_debug(self, _):
- """ event_debug - Display filesystem events as they are
- processed """
- self.fam.debug = True
-
- def do_packageresolve(self, args):
- """ packageresolve <hostname> [<package> [<package>...]] -
- Resolve packages for the given host, optionally specifying a
- set of packages """
- arglist = args.split(" ")
- if len(arglist) < 1:
- print(self._get_usage(self.do_packageresolve))
- return
-
- try:
- pkgs = self.plugins['Packages']
- except KeyError:
- print("Packages plugin not enabled")
- return
- pkgs.toggle_debug()
-
- hostname = arglist[0]
- metadata = self.build_metadata(hostname)
-
- indep = lxml.etree.Element("Independent")
- if len(arglist) > 1:
- structures = [lxml.etree.Element("Bundle", name="packages")]
- for arg in arglist[1:]:
- lxml.etree.SubElement(structures[0], "Package", name=arg)
- else:
- structures = self.GetStructures(metadata)
-
- pkgs._build_packages(metadata, indep, # pylint: disable=W0212
- structures)
- print("%d new packages added" % len(indep.getchildren()))
- if len(indep.getchildren()):
- print(" %s" % "\n ".join(lxml.etree.tostring(p)
- for p in indep.getchildren()))
-
- def do_packagesources(self, args):
- """ packagesources <hostname> - Show package sources """
- if not args:
- print(self._get_usage(self.do_packagesources))
- return
- if 'Packages' not in self.plugins:
- print("Packages plugin not enabled")
- return
- try:
- metadata = self.build_metadata(args)
- except Bcfg2.Server.Plugin.MetadataConsistencyError:
- print("Unable to build metadata for host %s" % args)
- return
- collection = self.plugins['Packages'].get_collection(metadata)
- print(collection.sourcelist())
-
- def do_query(self, args):
- """ query <-g group|-p profile|-b bundle> - Query clients """
- if len(args) == 0:
- print("\n".join(self.metadata.clients))
- return
- arglist = args.split(" ")
- if len(arglist) != 2:
- print(self._get_usage(self.do_query))
- return
-
- qtype, qparam = arglist
- if qtype == '-p':
- res = self.metadata.get_client_names_by_profiles(qparam.split(','))
- elif qtype == '-g':
- res = self.metadata.get_client_names_by_groups(qparam.split(','))
- elif qtype == '-b':
- res = self.metadata.get_client_names_by_bundles(qparam.split(','))
- else:
- print(self._get_usage(self.do_query))
- return
- print("\n".join(res))
-
- def do_profile(self, arg):
- """ profile <command> <args> - Profile a single bcfg2-info
- command """
- if not HAS_PROFILE:
- print("Profiling functionality not available.")
- return
- if len(arg) == 0:
- print(self._get_usage(self.do_profile))
- return
- prof = profile.Profile()
- prof.runcall(self.onecmd, arg)
- display_trace(prof)
-
- def run(self, args): # pylint: disable=W0221
- try:
- self.load_plugins()
- self.fam.handle_events_in_interval(1)
- if args:
- self.onecmd(" ".join(args))
- else:
- self.do_loop()
- finally:
- self.shutdown()
-
- def _daemonize(self):
- pass
-
- def _run(self):
- pass
-
- def _block(self):
- pass
-
-
-def build_usage():
- """ build usage message """
- cmd_blacklist = ["do_loop", "do_EOF"]
- usage = dict()
- for attrname in dir(InfoCore):
- attr = getattr(InfoCore, attrname)
-
- # shim for python 2.4, __func__ is im_func
- funcattr = getattr(attr, "__func__", getattr(attr, "im_func", None))
- if (funcattr is not None and
- funcattr.func_name not in cmd_blacklist and
- funcattr.func_name.startswith("do_") and
- funcattr.func_doc):
- usage[attr.__name__] = re.sub(r'\s+', ' ', attr.__doc__)
- return "Commands:\n" + "\n".join(usage[k] for k in sorted(usage.keys()))
-
-
-USAGE = build_usage()
-
-
-def main():
- optinfo = dict(profile=Bcfg2.Options.CORE_PROFILE,
- interactive=Bcfg2.Options.INTERACTIVE,
- interpreter=Bcfg2.Options.INTERPRETER)
- optinfo.update(Bcfg2.Options.INFO_COMMON_OPTIONS)
- setup = Bcfg2.Options.OptionParser(optinfo)
- 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)
- elif setup['profile'] and HAS_PROFILE:
- prof = profile.Profile()
- loop = prof.runcall(InfoCore)
- display_trace(prof)
- else:
- if setup['profile']:
- print("Profiling functionality not available.")
- loop = InfoCore()
-
- loop.run(setup['args'])
-
+from Bcfg2.Server.Info import CLI
if __name__ == '__main__':
- sys.exit(main())
+ sys.exit(CLI().run())