diff options
Diffstat (limited to 'src/sbin')
-rwxr-xr-x | src/sbin/bcfg2 | 7 | ||||
-rwxr-xr-x | src/sbin/bcfg2-admin | 4 | ||||
-rwxr-xr-x | src/sbin/bcfg2-build-reports | 306 | ||||
-rwxr-xr-x | src/sbin/bcfg2-crypt | 48 | ||||
-rwxr-xr-x | src/sbin/bcfg2-info | 190 | ||||
-rwxr-xr-x | src/sbin/bcfg2-lint | 40 | ||||
-rwxr-xr-x | src/sbin/bcfg2-report-collector | 4 | ||||
-rwxr-xr-x | src/sbin/bcfg2-server | 2 | ||||
-rwxr-xr-x | src/sbin/bcfg2-test | 3 |
9 files changed, 147 insertions, 457 deletions
diff --git a/src/sbin/bcfg2 b/src/sbin/bcfg2 index 444e86a7c..62f749b80 100755 --- a/src/sbin/bcfg2 +++ b/src/sbin/bcfg2 @@ -3,8 +3,8 @@ import sys import signal -import Bcfg2.Options from Bcfg2.Client.Client import Client +from Bcfg2.Options import load_option_parser, CLIENT_COMMON_OPTIONS def cb_sigint_handler(signum, frame): @@ -13,8 +13,7 @@ def cb_sigint_handler(signum, frame): def main(): - optinfo = Bcfg2.Options.CLIENT_COMMON_OPTIONS - setup = Bcfg2.Options.OptionParser(optinfo) + setup = load_option_parser(CLIENT_COMMON_OPTIONS) setup.parse(sys.argv[1:]) if setup['args']: @@ -23,7 +22,7 @@ def main(): raise SystemExit(1) signal.signal(signal.SIGINT, cb_sigint_handler) - return Client(setup).run() + return Client().run() if __name__ == '__main__': sys.exit(main()) diff --git a/src/sbin/bcfg2-admin b/src/sbin/bcfg2-admin index 14d188342..0e1e34c60 100755 --- a/src/sbin/bcfg2-admin +++ b/src/sbin/bcfg2-admin @@ -42,7 +42,7 @@ def main(): optinfo = dict() optinfo.update(Bcfg2.Options.CLI_COMMON_OPTIONS) optinfo.update(Bcfg2.Options.SERVER_COMMON_OPTIONS) - setup = Bcfg2.Options.OptionParser(optinfo) + setup = Bcfg2.Options.load_option_parser(optinfo) # override default help message to include description of all modes setup.hm = "Usage:\n\n%s\n%s" % (setup.buildHelpMessage(), create_description()) @@ -81,7 +81,7 @@ def main(): err = sys.exc_info()[1] log.error("Failed to load admin mode %s: %s" % (modname, err)) raise SystemExit(1) - mode = mode_cls(setup) + mode = mode_cls() try: return mode(setup['args'][1:]) finally: diff --git a/src/sbin/bcfg2-build-reports b/src/sbin/bcfg2-build-reports deleted file mode 100755 index 1c9e9ad97..000000000 --- a/src/sbin/bcfg2-build-reports +++ /dev/null @@ -1,306 +0,0 @@ -#!/usr/bin/env python - -""" -bcfg2-build-reports generates & distributes reports of statistic -information for Bcfg2.""" - -import copy -import getopt -import re -import os -import socket -import sys -from time import asctime, strptime -from lxml.etree import XML, XSLT, parse, Element, ElementTree, SubElement, tostring, XMLSyntaxError -# Compatibility imports -from Bcfg2.Compat import ConfigParser, cmp - -def generatereport(rspec, nrpt): - """ - generatereport creates and returns an ElementTree representation - of a report adhering to the XML spec for intermediate reports. - """ - reportspec = copy.deepcopy(rspec) - nodereprt = copy.deepcopy(nrpt) - - reportgood = reportspec.get("good", default = 'Y') - reportmodified = reportspec.get("modified", default = 'Y') - current_date = asctime()[:10] - - """Build regex of all the nodes we are reporting about.""" - pattern = re.compile( '|'.join([item.get("name") for item in reportspec.findall('Machine')])) - - for node in nodereprt.findall('Node'): - if not (node.findall("Statistics") and pattern.match(node.get('name'))): - # Don't know enough about node. - nodereprt.remove(node) - continue - - # Reduce to most recent Statistics entry. - statisticslist = node.findall('Statistics') - # This line actually sorts from most recent to oldest. - statisticslist.sort(lambda y, x: cmp(strptime(x.get("time")), strptime(y.get("time")))) - stats = statisticslist[0] - - [node.remove(item) for item in node.findall('Statistics')] - - # Add a good tag if node is good and we wnat to report such. - if reportgood == 'Y' and stats.get('state') == 'clean': - SubElement(stats,"Good") - - [stats.remove(item) for item in stats.findall("Bad") + stats.findall("Modified") if \ - item.getchildren() == []] - [stats.remove(item) for item in stats.findall("Modified") if reportmodified == 'N'] - - # Test for staleness -if stale add Stale tag. - if stats.get("time").find(current_date) == -1: - SubElement(stats,"Stale") - node.append(stats) - return nodereprt - -def mail(mailbody, confi): - """mail mails a previously generated report.""" - - try: - mailer = confi.get('statistics', 'sendmailpath') - except (ConfigParser.NoSectionError, ConfigParser.NoOptionError): - mailer = "/usr/sbin/sendmail" - # Open a pipe to the mail program and - # write the data to the pipe. - pipe = os.popen("%s -t" % mailer, 'w') - pipe.write(mailbody) - exitcode = pipe.close() - if exitcode: - print("Exit code: %s" % exitcode) - -def rss(reportxml, delivery, report): - """rss appends a new report to the specified rss file - keeping the last 9 articles. - """ - # Check and see if rss file exists. - for destination in delivery.findall('Destination'): - try: - fil = open(destination.attrib['address'], 'r') - olddoc = XML(fil.read()) - - # Defines the number of recent articles to keep. - items = olddoc.find("channel").findall("item")[0:9] - fil.close() - fil = open(destination.attrib['address'], 'w') - except (IOError, XMLSyntaxError): - fil = open(destination.attrib['address'], 'w') - items = [] - - rssdata = Element("rss") - channel = SubElement(rssdata, "channel") - rssdata.set("version", "2.0") - chantitle = SubElement(channel, "title") - chantitle.text = report.attrib['name'] - chanlink = SubElement(channel, "link") - - # This can later link to WWW report if one gets published - # simultaneously? - chanlink.text = "http://www.mcs.anl.gov/cobalt/bcfg2" - chandesc = SubElement(channel, "description") - chandesc.text = "Information regarding the 10 most recent bcfg2 runs." - - channel.append(XML(reportxml)) - - if items != []: - for item in items: - channel.append(item) - - tree = tostring(rssdata, xml_declaration=False).decode('UTF-8') - fil.write(tree) - fil.close() - -def www(reportxml, delivery): - """www outputs report to.""" - - # This can later link to WWW report if one gets published - # simultaneously? - for destination in delivery.findall('Destination'): - fil = open(destination.attrib['address'], 'w') - - fil.write(reportxml) - fil.close() - -def fileout(reportxml, delivery): - """Outputs to plain text file.""" - for destination in delivery.findall('Destination'): - fil = open(destination.attrib['address'], 'w') - - fil.write(reportxml) - fil.close() - -def pretty_print(element, level=0): - """Produce a pretty-printed text representation of element.""" - if element.text: - fmt = "%s<%%s %%s>%%s</%%s>" % (level*" ") - data = (element.tag, (" ".join(["%s='%s'" % keyval for keyval in list(element.attrib.items())])), - element.text, element.tag) - if element._children: - fmt = "%s<%%s %%s>\n" % (level*" ",) + (len(element._children) * "%s") + "%s</%%s>\n" % (level*" ") - data = (element.tag, ) + (" ".join(["%s='%s'" % keyval for keyval in list(element.attrib.items())]),) - data += tuple([pretty_print(entry, level+2) for entry in element._children]) + (element.tag, ) - else: - fmt = "%s<%%s %%s/>\n" % (level * " ") - data = (element.tag, " ".join(["%s='%s'" % keyval for keyval in list(element.attrib.items())])) - return fmt % data - - -if __name__ == '__main__': - all=False - if '-C' in sys.argv: - cfpath = sys.argv[sys.argv.index('-C') + 1] - else: - cfpath = '/etc/bcfg2.conf' - c = ConfigParser.ConfigParser() - c.read([cfpath]) - configpath = "%s/etc/report-configuration.xml" % c.get('server', 'repository') - statpath = "%s/etc/statistics.xml" % c.get('server', 'repository') - clientsdatapath = "%s/Metadata/clients.xml" % c.get('server', 'repository') - try: - prefix = c.get('server', 'prefix') - except (ConfigParser.NoSectionError, ConfigParser.NoOptionError): - prefix = '/usr' - - transformpath = "/%s/share/bcfg2/xsl-transforms/" % (prefix) - #websrcspath = "/usr/share/bcfg2/web-rprt-srcs/" - - try: - opts, args = getopt.getopt(sys.argv[1:], "C:hAc:Ns:", ["help", "all", "config=", "stats="]) - except getopt.GetoptError: - mesg = sys.exc_info()[1] - # Print help information and exit: - print("%s\nUsage:\nbcfg2-build-reports [-h][-A (include ALL clients)] [-c <configuration-file>] [-s <statistics-file>]" % (mesg)) - raise SystemExit(2) - for o, a in opts: - if o in ("-h", "--help"): - print("Usage:\nbcfg2-build-reports [-h] [-c <configuration-file>] [-s <statistics-file>]") - raise SystemExit - if o in ("-A", "--all"): - all=True - if o in ("-c", "--config"): - configpath = a - if o in ("-s", "--stats"): - statpath = a - - - """Reads data & config files.""" - try: - statsdata = XML(open(statpath).read()) - except (IOError, XMLSyntaxError): - print("bcfg2-build-reports: Failed to parse %s"%(statpath)) - raise SystemExit(1) - try: - configdata = XML(open(configpath).read()) - except (IOError, XMLSyntaxError): - print("bcfg2-build-reports: Failed to parse %s"%(configpath)) - raise SystemExit(1) - try: - clientsdata = XML(open(clientsdatapath).read()) - except (IOError, XMLSyntaxError): - print("bcfg2-build-reports: Failed to parse %s"%(clientsdatapath)) - raise SystemExit(1) - - # Merge data from three sources. - nodereport = Element("Report", attrib={"time" : asctime()}) - # Should all of the other info in Metadata be appended? - # What about all of the package stuff for other types of reports? - for client in clientsdata.findall("Client"): - nodel = Element("Node", attrib={"name" : client.get("name")}) - nodel.append(client) - for nod in statsdata.findall("Node"): - if client.get('name').find(nod.get('name')) == 0: - for statel in nod.findall("Statistics"): - nodel.append(statel) - nodereport.append(nodel) - - if all: - for nod in statsdata.findall("Node"): - for client in clientsdata.findall("Client"): - if client.get('name').find(nod.get('name')) == 0: - break - else: - nodel = Element("Node", attrib={"name" : nod.get("name")}) - client = Element("Client", attrib={"name" : nod.get("name"), "profile" : "default"}) - nodel.append(client) - for statel in nod.findall("Statistics"): - nodel.append(statel) - nodereport.append(nodel) - - - for reprt in configdata.findall('Report'): - nodereport.set("name", reprt.get("name", default="BCFG Report")) - - if reprt.get('refresh-time') != None: - nodereport.set("refresh-time", reprt.get("refresh-time", default="600")) - - procnodereport = generatereport(reprt, nodereport) - - for deliv in reprt.findall('Delivery'): - # Is a deepcopy of procnodereport necessary? - - delivtype = deliv.get('type', default='nodes-digest') - deliverymechanism = deliv.get('mechanism', default='www') - - # Apply XSLT, different ones based on report type, and options - if deliverymechanism == 'null-operator': # Special Cases - fileout(tostring(ElementTree(procnodereport).getroot(), xml_declaration=False).decode('UTF-8'), deliv) - break - transform = delivtype + '-' + deliverymechanism + '.xsl' - - try: # Make sure valid stylesheet is selected. - os.stat(transformpath + transform) - except: - print("bcfg2-build-reports: Invalid report type or delivery mechanism.\n Can't find: "\ - + transformpath + transform) - raise SystemExit(1) - - try: # Try to parse stylesheet. - stylesheet = XSLT(parse(transformpath + transform)) - except: - print("bcfg2-build-reports: invalid XSLT transform file.") - raise SystemExit(1) - - if deliverymechanism == 'mail': - if delivtype == 'nodes-individual': - reportdata = copy.deepcopy(procnodereport) - for noden in reportdata.findall("Node"): - [reportdata.remove(y) for y in reportdata.findall("Node")] - reportdata.append(noden) - result = stylesheet.apply(ElementTree(reportdata)) - outputstring = stylesheet.tostring(result) - - if not outputstring == None: - toastring = '' - for desti in deliv.findall("Destination"): - toastring = "%s%s " % \ - (toastring, desti.get('address')) - # Prepend To: and From: - outputstring = "To: %s\nFrom: root@%s\n%s"% \ - (toastring, socket.getfqdn(), outputstring) - mail(outputstring, c) #call function to send - - else: - reportdata = copy.deepcopy(procnodereport) - - result = stylesheet.apply(ElementTree(reportdata)) - outputstring = stylesheet.tostring(result) - - if not outputstring == None: - toastring = '' - for desti in deliv.findall("Destination"): - toastring = "%s%s " % \ - (toastring, desti.get('address')) - # Prepend To: and From: - outputstring = "To: %s\nFrom: root@%s\n%s"% \ - (toastring, socket.getfqdn(), outputstring) - mail(outputstring, c) #call function to send - else: - outputstring = tostring(stylesheet.apply(ElementTree(procnodereport)).getroot(), xml_declaration=False).decode('UTF-8') - if deliverymechanism == 'rss': - rss(outputstring, deliv, reprt) - else: # Must be deliverymechanism == 'www': - www(outputstring, deliv) diff --git a/src/sbin/bcfg2-crypt b/src/sbin/bcfg2-crypt index 7102d06a9..6a92a0260 100755 --- a/src/sbin/bcfg2-crypt +++ b/src/sbin/bcfg2-crypt @@ -12,7 +12,7 @@ import Bcfg2.Options from Bcfg2.Server import XMLParser from Bcfg2.Compat import input # pylint: disable=W0622 try: - import Bcfg2.Encryption + import Bcfg2.Server.Encryption except ImportError: print("Could not import %s. Is M2Crypto installed?" % sys.exc_info()[1]) raise SystemExit(1) @@ -28,7 +28,7 @@ class CryptoTool(object): def __init__(self, filename, setup): self.setup = setup self.logger = logging.getLogger(self.__class__.__name__) - self.passphrases = Bcfg2.Encryption.get_passphrases(self.setup) + self.passphrases = Bcfg2.Server.Encryption.get_passphrases(self.setup) self.filename = filename try: @@ -43,8 +43,9 @@ class CryptoTool(object): def _get_passphrase(self): """ get the passphrase for the current file """ - if (not self.setup.cfp.has_section(Bcfg2.Encryption.CFG_SECTION) or - len(Bcfg2.Encryption.get_passphrases(self.setup)) == 0): + if (not self.setup.cfp.has_section( + Bcfg2.Server.Encryption.CFG_SECTION) or + len(Bcfg2.Server.Encryption.get_passphrases(self.setup)) == 0): raise PassphraseError("No passphrases available in %s" % self.setup['configfile']) @@ -53,10 +54,10 @@ class CryptoTool(object): pname = self.setup['passphrase'] if pname: - if self.setup.cfp.has_option(Bcfg2.Encryption.CFG_SECTION, + if self.setup.cfp.has_option(Bcfg2.Server.Encryption.CFG_SECTION, pname): - passphrase = self.setup.cfp.get(Bcfg2.Encryption.CFG_SECTION, - pname) + passphrase = self.setup.cfp.get( + Bcfg2.Server.Encryption.CFG_SECTION, pname) self.logger.debug("Using passphrase %s specified on command " "line" % pname) return (pname, passphrase) @@ -64,7 +65,7 @@ class CryptoTool(object): raise PassphraseError("Could not find passphrase %s in %s" % (pname, self.setup['configfile'])) else: - pnames = Bcfg2.Encryption.get_passphrases(self.setup) + pnames = Bcfg2.Server.Encryption.get_passphrases() if len(pnames) == 1: pname = pnames.keys()[0] passphrase = pnames[pname] @@ -123,9 +124,9 @@ class CfgEncryptor(Encryptor): self.setup['configfile']) def encrypt(self): - return Bcfg2.Encryption.ssl_encrypt( + return Bcfg2.Server.Encryption.ssl_encrypt( self.data, self.passphrase, - Bcfg2.Encryption.get_algorithm(self.setup)) + Bcfg2.Server.Encryption.get_algorithm(self.setup)) def get_destination_filename(self, original_filename): return original_filename + ".crypt" @@ -138,10 +139,10 @@ class CfgDecryptor(Decryptor): """ decrypt the given file, returning the plaintext data """ if self.passphrase: try: - return Bcfg2.Encryption.ssl_decrypt( + return Bcfg2.Server.Encryption.ssl_decrypt( self.data, self.passphrase, - Bcfg2.Encryption.get_algorithm(self.setup)) - except Bcfg2.Encryption.EVPError: + Bcfg2.Server.Encryption.get_algorithm(self.setup)) + except Bcfg2.Server.Encryption.EVPError: self.logger.info("Could not decrypt %s with the " "specified passphrase" % self.filename) return False @@ -152,10 +153,11 @@ class CfgDecryptor(Decryptor): return False else: # no passphrase given, brute force try: - return Bcfg2.Encryption.bruteforce_decrypt( + return Bcfg2.Server.Encryption.bruteforce_decrypt( self.data, passphrases=self.passphrases.values(), - algorithm=Bcfg2.Encryption.get_algorithm(self.setup)) - except Bcfg2.Encryption.EVPError: + algorithm=Bcfg2.Server.Encryption.get_algorithm( + self.setup)) + except Bcfg2.Server.Encryption.EVPError: self.logger.info("Could not decrypt %s with any passphrase" % self.filename) @@ -244,9 +246,9 @@ class PropertiesEncryptor(Encryptor, PropertiesCryptoMixin): except PassphraseError: self.logger.error(str(sys.exc_info()[1])) return False - elt.text = Bcfg2.Encryption.ssl_encrypt( + elt.text = Bcfg2.Server.Encryption.ssl_encrypt( elt.text, passphrase, - Bcfg2.Encryption.get_algorithm(self.setup)).strip() + Bcfg2.Server.Encryption.get_algorithm(self.setup)).strip() elt.set("encrypted", pname) return xdata @@ -266,9 +268,9 @@ class PropertiesDecryptor(Decryptor, PropertiesCryptoMixin): except PassphraseError: self.logger.error(str(sys.exc_info()[1])) return False - decrypted = Bcfg2.Encryption.ssl_decrypt( + decrypted = Bcfg2.Server.Encryption.ssl_decrypt( elt.text, passphrase, - Bcfg2.Encryption.get_algorithm(self.setup)).strip() + Bcfg2.Server.Encryption.get_algorithm(self.setup)).strip() try: elt.text = decrypted.encode('ascii', 'xmlcharrefreplace') elt.set("encrypted", pname) @@ -290,10 +292,10 @@ def main(): # pylint: disable=R0912,R0915 optinfo = dict(interactive=Bcfg2.Options.INTERACTIVE) optinfo.update(Bcfg2.Options.CRYPT_OPTIONS) optinfo.update(Bcfg2.Options.CLI_COMMON_OPTIONS) - setup = Bcfg2.Options.OptionParser(optinfo) + setup = Bcfg2.Options.load_option_parser(optinfo) setup.hm = " bcfg2-crypt [options] <filename>\nOptions:\n%s" % \ setup.buildHelpMessage() - setup.parse(sys.argv[1:]) + setup.parse() if not setup['args']: print(setup.hm) @@ -430,7 +432,7 @@ def main(): # pylint: disable=R0912,R0915 tool.write(data) if (setup['remove'] and - tool.get_destination_filename(fname) != fname): + tool.get_destination_filename(fname) != fname): try: os.unlink(fname) except IOError: diff --git a/src/sbin/bcfg2-info b/src/sbin/bcfg2-info index 539ae3115..5eef72350 100755 --- a/src/sbin/bcfg2-info +++ b/src/sbin/bcfg2-info @@ -16,6 +16,7 @@ import Bcfg2.Options import Bcfg2.Server.Core import Bcfg2.Server.Plugin import Bcfg2.Client.Tools.POSIX +from Bcfg2.Compat import unicode # pylint: disable=W0622 try: try: @@ -115,11 +116,15 @@ def load_interpreters(): class InfoCore(cmd.Cmd, Bcfg2.Server.Core.BaseCore): """Main class for bcfg2-info.""" - def __init__(self, setup): + doc_header = "bcfg2-info commands (type help <command>):" + prompt = 'bcfg2-info> ' + + def __init__(self): cmd.Cmd.__init__(self) - Bcfg2.Server.Core.BaseCore.__init__(self, setup=setup) - self.prompt = '> ' - self.cont = True + self.setup = Bcfg2.Options.get_option_parser() + self.setup.update(Bcfg2.Options.SERVER_COMMON_OPTIONS) + self.setup.update(dict(interpreter=Bcfg2.Options.INTERPRETER)) + Bcfg2.Server.Core.BaseCore.__init__(self) def _get_client_list(self, hostglobs): """ given a host glob, get a list of clients that match it """ @@ -144,37 +149,15 @@ class InfoCore(cmd.Cmd, Bcfg2.Server.Core.BaseCore): 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 """ + """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)) + print(self.do_debug.__doc__) return - self.cont = False scriptmode = False interactive = True for opt in opts: @@ -201,24 +184,23 @@ class InfoCore(cmd.Cmd, Bcfg2.Server.Core.BaseCore): ", ".join(interpreters.keys())) def do_quit(self, _): - """ quit|exit - Exit program """ + """quit|exit + Exit program""" + print("") # put user's prompt on a new line 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""" + """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""" + """build [-f] <hostname> <filename> + Build config for hostname, writing to filename""" alist = args.split() path_force = False for arg in alist: @@ -240,7 +222,7 @@ class InfoCore(cmd.Cmd, Bcfg2.Server.Core.BaseCore): err = sys.exc_info()[1] print("Failed to write File %s: %s" % (ofile, err)) else: - print(self._get_usage(self.do_build)) + print(self.do_build.__doc__) def help_builddir(self): """Display help for builddir command.""" @@ -258,8 +240,8 @@ 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""" + """ builddir [-f] <hostname> <dirname> + Build config for hostname, writing separate files to dirname""" alist = args.split() path_force = False if '-f' in args: @@ -284,19 +266,18 @@ Bcfg2 client itself.""") posix = Bcfg2.Client.Tools.POSIX.POSIX(MockLog(), self.setup, client_config) - states = dict() - posix.Inventory(states) - posix.Install(list(states.keys()), states) + states = posix.Inventory() + posix.Install(list(states.keys())) else: print('Error: Incorrect number of parameters.') - self.help_builddir() + print(self.do_builddir.__doc__) def do_buildall(self, args): - """ buildall <directory> [<hostnames*>] - Build configs for - all clients in directory """ + """buildall <directory> [<hostnames*>] + Build configs for all clients in directory""" alist = args.split() if len(alist) < 1: - print(self._get_usage(self.do_buildall)) + print(self.do_buildall.__doc__) return destdir = alist[0] @@ -315,20 +296,20 @@ Bcfg2 client itself.""") client + ".xml"))) def do_buildallfile(self, args): - """ buildallfile <directory> <filename> [<hostnames*>] - Build - config file for all clients in directory """ + """ 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)) + print(self.do_buildallfile.__doc__) 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)) + print(self.do_buildallfile.__doc__) return destdir = args[0] @@ -352,9 +333,8 @@ Bcfg2 client itself.""") filename, client)) def do_buildfile(self, args): - """ buildfile [-f <outfile>] [--altsrc=<altsrc>] <filename> - <hostname> - Build config file for hostname (not written to - disk)""" + """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: @@ -396,11 +376,11 @@ Bcfg2 client itself.""") print(data) def do_buildbundle(self, args): - """ buildbundle <bundle> <hostname> - Render a templated - bundle for hostname (not written to disk) """ + """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 + print(self.do_buildbundle.__doc__) + return bname, client = args.split() try: @@ -418,8 +398,8 @@ Bcfg2 client itself.""") err)) def do_automatch(self, args): - """ automatch [-f] <propertyfile> <hostname> - Perform automatch on - a Properties file """ + """automatch [-f] <propertyfile> <hostname> + Perform automatch on a Properties file""" alist = args.split() force = False for arg in alist: @@ -427,7 +407,7 @@ Bcfg2 client itself.""") alist.remove('-f') force = True if len(alist) != 2: - print(self._get_usage(self.do_automatch)) + print(self.do_automatch.__doc__) return if 'Properties' not in self.plugins: @@ -449,7 +429,8 @@ Bcfg2 client itself.""") pretty_print=True).decode('UTF-8')) def do_bundles(self, _): - """ bundles - Print out group/bundle info """ + """bundles + Print out group/bundle info""" data = [('Group', 'Bundles')] groups = list(self.metadata.groups.keys()) groups.sort() @@ -459,7 +440,8 @@ Bcfg2 client itself.""") print_tabular(data) def do_clients(self, _): - """ clients - Print out client/profile info """ + """clients + Print out client/profile info""" data = [('Client', 'Profile')] for client in sorted(self.metadata.list_clients()): imd = self.metadata.get_initial_metadata(client) @@ -467,7 +449,8 @@ Bcfg2 client itself.""") print_tabular(data) def do_config(self, _): - """ config - Print out the current configuration of Bcfg2""" + """config + Print out the current configuration of Bcfg2""" output = [ ('Description', 'Value'), ('Path Bcfg2 repository', self.setup['repo']), @@ -483,16 +466,16 @@ Bcfg2 client itself.""") 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""" + """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)) + print(self.do_probes.__doc__) return hostname = alist[0] if pretty: @@ -518,11 +501,11 @@ Bcfg2 client itself.""") pretty_print=True).decode('UTF-8')) def do_showentries(self, args): - """ showentries <hostname> <type> - Show abstract - configuration entries for a given host """ + """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)) + print(self.do_showentries.__doc__) return client = args.split()[0] try: @@ -545,7 +528,8 @@ Bcfg2 client itself.""") print_tabular(output) def do_groups(self, _): - """ groups - Print out group info """ + """groups + Print out group info""" data = [("Groups", "Profile", "Category")] grouplist = list(self.metadata.groups.keys()) grouplist.sort() @@ -559,10 +543,10 @@ Bcfg2 client itself.""") print_tabular(data) def do_showclient(self, args): - """ showclient <client> [<client> ...] - Show metadata for the - given hosts """ + """showclient <client> [<client> ...] + Show metadata for the given hosts""" if not len(args): - print(self._get_usage(self.do_showclient)) + print(self.do_showclient.__doc__) return for client in args.split(): try: @@ -601,8 +585,8 @@ Bcfg2 client itself.""") print("=" * 80) def do_mappings(self, args): - """ mappings <type*> <name*> - Print generator mappings for - optional type and name """ + """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()) @@ -625,17 +609,17 @@ Bcfg2 client itself.""") print_tabular(data) def do_event_debug(self, _): - """ event_debug - Display filesystem events as they are - processed """ + """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 """ + """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)) + print(self.do_packageresolve.__doc__) return try: @@ -660,13 +644,15 @@ Bcfg2 client itself.""") 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())) + print(" %s" % "\n ".join( + lxml.etree.tostring(p, encoding=unicode) + for p in indep.getchildren())) def do_packagesources(self, args): - """ packagesources <hostname> - Show package sources """ + """packagesources <hostname> + Show package sources""" if not args: - print(self._get_usage(self.do_packagesources)) + print(self.do_packagesources.__doc__) return if 'Packages' not in self.plugins: print("Packages plugin not enabled") @@ -680,13 +666,14 @@ Bcfg2 client itself.""") print(collection.sourcelist()) def do_query(self, args): - """ query <-g group|-p profile|-b bundle> - Query clients """ + """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)) + print(self.do_query.__doc__) return qtype, qparam = arglist @@ -697,18 +684,18 @@ Bcfg2 client itself.""") elif qtype == '-b': res = self.metadata.get_client_names_by_bundles(qparam.split(',')) else: - print(self._get_usage(self.do_query)) + print(self.do_query.__doc__) return print("\n".join(res)) def do_profile(self, arg): - """ profile <command> <args> - Profile a single bcfg2-info - command """ + """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)) + print(self.do_profile.__doc__) return prof = profile.Profile() prof.runcall(self.onecmd, arg) @@ -721,7 +708,14 @@ Bcfg2 client itself.""") if args: self.onecmd(" ".join(args)) else: - self.do_loop() + try: + self.cmdloop('Welcome to bcfg2-info\n' + 'Type "help" for more information') + except KeyboardInterrupt: + print("\nCtrl-C pressed exiting...") + self.do_exit([]) + except Bcfg2.Server.Plugin.PluginExecutionError: + pass finally: self.shutdown() @@ -736,7 +730,7 @@ Bcfg2 client itself.""") def build_usage(): - """ build usage message """ + """build usage message""" cmd_blacklist = ["do_loop", "do_EOF"] usage = dict() for attrname in dir(InfoCore): @@ -762,7 +756,7 @@ def main(): command_timeout=Bcfg2.Options.CLIENT_COMMAND_TIMEOUT) optinfo.update(Bcfg2.Options.INFO_COMMON_OPTIONS) setup = Bcfg2.Options.OptionParser(optinfo) - setup.hm = "\n".join([" bcfg2-info [options] [command <command args>]", + setup.hm = "\n".join(["bcfg2-info [options] [command <command args>]", "Options:", setup.buildHelpMessage(), USAGE]) @@ -782,12 +776,12 @@ def main(): sys.exit(0) elif setup['profile'] and HAS_PROFILE: prof = profile.Profile() - loop = prof.runcall(InfoCore, setup) + loop = prof.runcall(InfoCore) display_trace(prof) else: if setup['profile']: print("Profiling functionality not available.") - loop = InfoCore(setup) + loop = InfoCore() loop.run(setup['args']) diff --git a/src/sbin/bcfg2-lint b/src/sbin/bcfg2-lint index 9ceb1dd04..27d8d4291 100755 --- a/src/sbin/bcfg2-lint +++ b/src/sbin/bcfg2-lint @@ -14,37 +14,36 @@ import Bcfg2.Server.Lint LOGGER = logging.getLogger('bcfg2-lint') -def run_serverless_plugins(plugins, setup=None, errorhandler=None, files=None): +def run_serverless_plugins(plugins, errorhandler=None, files=None): """ Run serverless plugins """ LOGGER.debug("Running serverless plugins") for plugin_name, plugin in list(plugins.items()): - run_plugin(plugin, plugin_name, errorhandler=errorhandler, - setup=setup, files=files) + run_plugin(plugin, plugin_name, errorhandler=errorhandler, files=files) -def run_server_plugins(plugins, setup=None, errorhandler=None, files=None): +def run_server_plugins(plugins, errorhandler=None, files=None): """ run plugins that require a running server to run """ - core = load_server(setup) + core = load_server() try: LOGGER.debug("Running server plugins") for plugin_name, plugin in list(plugins.items()): run_plugin(plugin, plugin_name, args=[core], - errorhandler=errorhandler, setup=setup, files=files) + errorhandler=errorhandler, files=files) finally: core.shutdown() -def run_plugin(plugin, plugin_name, setup=None, errorhandler=None, - args=None, files=None): +def run_plugin(plugin, plugin_name, errorhandler=None, args=None, files=None): """ run a single plugin, server-ful or serverless. """ LOGGER.debug(" Running %s" % plugin_name) if args is None: args = [] if errorhandler is None: - errorhandler = get_errorhandler(setup) + errorhandler = get_errorhandler() - if setup is not None and setup.cfp.has_section(plugin_name): + setup = Bcfg2.Options.get_option_parser() + if setup.cfp.has_section(plugin_name): arg = setup for key, val in setup.cfp.items(plugin_name): arg[key] = val @@ -60,8 +59,9 @@ def run_plugin(plugin, plugin_name, setup=None, errorhandler=None, return rv -def get_errorhandler(setup): +def get_errorhandler(): """ get a Bcfg2.Server.Lint.ErrorHandler object """ + setup = Bcfg2.Options.get_option_parser() if setup.cfp.has_section("errors"): errors = dict(setup.cfp.items("errors")) else: @@ -69,9 +69,9 @@ def get_errorhandler(setup): return Bcfg2.Server.Lint.ErrorHandler(errors=errors) -def load_server(setup): +def load_server(): """ load server """ - core = Bcfg2.Server.Core.BaseCore(setup) + core = Bcfg2.Server.Core.BaseCore() core.load_plugins() core.block_for_fam_events(handle_events=True) return core @@ -89,8 +89,9 @@ def load_plugin(module, obj_name=None): return getattr(mod, obj_name) -def load_plugins(setup): +def load_plugins(): """ get list of plugins to run """ + setup = Bcfg2.Options.get_option_parser() if setup['args']: plugin_list = setup['args'] elif "bcfg2-repo-validate" in sys.argv[0]: @@ -152,7 +153,7 @@ def main(): lint_plugins=Bcfg2.Options.LINT_PLUGINS) optinfo.update(Bcfg2.Options.CLI_COMMON_OPTIONS) optinfo.update(Bcfg2.Options.SERVER_COMMON_OPTIONS) - setup = Bcfg2.Options.OptionParser(optinfo) + setup = Bcfg2.Options.load_option_parser(optinfo) setup.parse(sys.argv[1:]) log_args = dict(to_syslog=setup['syslog'], to_console=logging.WARNING) @@ -168,9 +169,8 @@ def main(): else: files = None - (serverlessplugins, serverplugins) = load_plugins(setup) - - errorhandler = get_errorhandler(setup) + (serverlessplugins, serverplugins) = load_plugins() + errorhandler = get_errorhandler() if setup['showerrors']: for plugin in serverplugins.values() + serverlessplugins.values(): @@ -182,7 +182,7 @@ def main(): raise SystemExit(0) run_serverless_plugins(serverlessplugins, errorhandler=errorhandler, - setup=setup, files=files) + files=files) if serverplugins: if errorhandler.errors: @@ -198,7 +198,7 @@ def main(): "plugins") else: run_server_plugins(serverplugins, errorhandler=errorhandler, - setup=setup, files=files) + files=files) if errorhandler.errors or errorhandler.warnings or setup['verbose']: print("%d errors" % errorhandler.errors) diff --git a/src/sbin/bcfg2-report-collector b/src/sbin/bcfg2-report-collector index 594be13bf..ae6d3b167 100755 --- a/src/sbin/bcfg2-report-collector +++ b/src/sbin/bcfg2-report-collector @@ -18,8 +18,8 @@ def main(): web_configfile=Bcfg2.Options.WEB_CFILE) optinfo.update(Bcfg2.Options.CLI_COMMON_OPTIONS) optinfo.update(Bcfg2.Options.REPORTING_COMMON_OPTIONS) - setup = Bcfg2.Options.OptionParser(optinfo) - setup.parse(sys.argv[1:]) + setup = Bcfg2.Options.load_option_parser(optinfo) + setup.parse() # run collector try: diff --git a/src/sbin/bcfg2-server b/src/sbin/bcfg2-server index 4c4a71fa7..beb19cef6 100755 --- a/src/sbin/bcfg2-server +++ b/src/sbin/bcfg2-server @@ -17,7 +17,7 @@ def main(): optinfo.update(Bcfg2.Options.CLI_COMMON_OPTIONS) optinfo.update(Bcfg2.Options.SERVER_COMMON_OPTIONS) optinfo.update(Bcfg2.Options.DAEMON_COMMON_OPTIONS) - setup = Bcfg2.Options.OptionParser(optinfo) + setup = Bcfg2.Options.load_option_parser(optinfo) setup.parse(sys.argv[1:]) # check whether the specified bcfg2.conf exists if not os.path.exists(setup['configfile']): diff --git a/src/sbin/bcfg2-test b/src/sbin/bcfg2-test index 7c38a65d8..564ddec49 100755 --- a/src/sbin/bcfg2-test +++ b/src/sbin/bcfg2-test @@ -137,6 +137,7 @@ class ClientTest(TestCase): "Configuration contains unknown packages: %s" % \ ", ".join(unknown_pkgs) + # check for render failures failures = [] msg = output + ["Failures:"] for failure in config.xpath('//*[@failure]'): @@ -210,7 +211,7 @@ def parse_args(): optinfo.update(Bcfg2.Options.CLI_COMMON_OPTIONS) optinfo.update(Bcfg2.Options.SERVER_COMMON_OPTIONS) - setup = Bcfg2.Options.OptionParser(optinfo) + setup = Bcfg2.Options.load_option_parser(optinfo) setup.hm = \ "bcfg2-test [options] [client] [client] [...]\nOptions:\n %s" % \ setup.buildHelpMessage() |