From 39f684b6862b96d3d5a918fd1028740ae8d8d174 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Thu, 8 Nov 2012 14:33:51 -0500 Subject: SSLCA: improved error, debug messages --- src/lib/Bcfg2/Server/Plugins/SSLCA.py | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/lib/Bcfg2/Server/Plugins/SSLCA.py b/src/lib/Bcfg2/Server/Plugins/SSLCA.py index ab55425a6..2a621eeb0 100644 --- a/src/lib/Bcfg2/Server/Plugins/SSLCA.py +++ b/src/lib/Bcfg2/Server/Plugins/SSLCA.py @@ -1,11 +1,12 @@ """ The SSLCA generator handles the creation and management of ssl certificates and their keys. """ +import os +import sys import Bcfg2.Server.Plugin import Bcfg2.Options import lxml.etree import tempfile -import os from subprocess import Popen, PIPE, STDOUT from Bcfg2.Compat import ConfigParser, md5 @@ -107,6 +108,7 @@ class SSLCA(Bcfg2.Server.Plugin.GroupSpool): filename = os.path.join(path, "%s.H_%s" % (os.path.basename(path), metadata.hostname)) if filename not in list(self.entries.keys()): + self.logger.info("SSLCA: Generating new key %s" % filename) key = self.build_key(entry) open(self.data + filename, 'w').write(key) entry.text = key @@ -130,6 +132,7 @@ class SSLCA(Bcfg2.Server.Plugin.GroupSpool): cmd = ["openssl", "genrsa", bits] elif ktype == 'dsa': cmd = ["openssl", "dsaparam", "-noout", "-genkey", bits] + self.debug_log("SSLCA: Generating new key: %s" % " ".join(cmd)) return Popen(cmd, stdout=PIPE).stdout.read() def get_cert(self, entry, metadata): @@ -151,10 +154,11 @@ class SSLCA(Bcfg2.Server.Plugin.GroupSpool): self.core.Bind(el, metadata) # check if we have a valid hostfile - if (filename in list(self.entries.keys()) and + if (filename in self.entries.keys() and self.verify_cert(filename, key_filename, entry)): entry.text = self.entries[filename].data else: + self.logger.info("SSLCA: Generating new cert %s" % filename) cert = self.build_cert(key_filename, entry, metadata) open(self.data + filename, 'w').write(cert) self.entries[filename] = self.__child__(self.data + filename) @@ -241,12 +245,19 @@ class SSLCA(Bcfg2.Server.Plugin.GroupSpool): "-days", days, "-batch"] if passphrase: cmd.extend(["-passin", "pass:%s" % passphrase]) - cert = Popen(cmd, stdout=PIPE).stdout.read() + self.debug_log("SSLCA: Generating new certificate: %s" % " ".join(cmd)) + proc = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE) + (cert, err) = proc.communicate() + if proc.wait(): + raise Bcfg2.Server.Plugin.PluginExecutionError( + "SSLCA: Failed to generate cert: %s" % + err.splitlines()[-1]) # pylint: disable=E1103 try: os.unlink(req_config) os.unlink(req) except OSError: - self.logger.error("Failed to unlink temporary files") + self.logger.error("SSLCA: Failed to unlink temporary files: %s" % + sys.exc_info()[1]) if (self.cert_specs[entry.get('name')]['append_chain'] and self.CAs[ca]['chaincert']): cert += open(self.CAs[ca]['chaincert']).read() @@ -303,5 +314,6 @@ class SSLCA(Bcfg2.Server.Plugin.GroupSpool): key = self.data + key_filename cmd = ["openssl", "req", "-new", "-config", req_config, "-days", days, "-key", key, "-text", "-out", req] + self.debug_log("SSLCA: Generating new CSR: %s" % " ".join(cmd)) Popen(cmd, stdout=PIPE).wait() return req -- cgit v1.2.3-1-g7c22 From 632a2cb0ad49bba32cc1c0c5451a46f57170de63 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Thu, 8 Nov 2012 14:34:20 -0500 Subject: Metadata: improved error message from address resolution failure during client authn --- src/lib/Bcfg2/Server/Plugins/Metadata.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/lib/Bcfg2/Server/Plugins/Metadata.py b/src/lib/Bcfg2/Server/Plugins/Metadata.py index 8b0fc16ce..0ab72f2c5 100644 --- a/src/lib/Bcfg2/Server/Plugins/Metadata.py +++ b/src/lib/Bcfg2/Server/Plugins/Metadata.py @@ -967,9 +967,10 @@ class Metadata(Bcfg2.Server.Plugin.Metadata, return self.aliases[cname] return cname except socket.herror: - warning = "address resolution error for %s" % address - self.logger.warning(warning) - raise Bcfg2.Server.Plugin.MetadataConsistencyError(warning) + err = "Address resolution error for %s: %s" % (address, + sys.exc_info()[1]) + self.logger.error(err) + raise Bcfg2.Server.Plugin.MetadataConsistencyError(err) def _merge_groups(self, client, groups, categories=None): """ set group membership based on the contents of groups.xml -- cgit v1.2.3-1-g7c22 From 0244d10e313ff57265b3b910c4b406c5112aa9c3 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Thu, 8 Nov 2012 14:34:36 -0500 Subject: Packages: fixed yum cachefiles property --- src/lib/Bcfg2/Server/Plugins/Packages/Yum.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py b/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py index 59e7a206e..a7129fc7a 100644 --- a/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py +++ b/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py @@ -357,7 +357,7 @@ class YumCollection(Collection): def cachefiles(self): """ A list of the full path to all cachefiles used by this collection.""" - cachefiles = set(Collection.cachefiles(self)) + cachefiles = set(Collection.cachefiles.fget(self)) if self.cachefile: cachefiles.add(self.cachefile) return list(cachefiles) -- cgit v1.2.3-1-g7c22 From 5f263d88822324d98350fc660b3ca0b077bd1501 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Mon, 12 Nov 2012 09:02:54 -0500 Subject: flush input buffers before accepting stdin --- src/lib/Bcfg2/Client/Frame.py | 5 +++ src/lib/Bcfg2/Client/Tools/Action.py | 7 ++++ src/lib/Bcfg2/Client/Tools/__init__.py | 6 ++++ src/lib/Bcfg2/Server/Admin/Init.py | 59 ++++++++++++++++++++-------------- src/lib/Bcfg2/Server/Admin/Pull.py | 8 ++++- src/sbin/bcfg2-crypt | 19 +++++++---- 6 files changed, 72 insertions(+), 32 deletions(-) (limited to 'src') diff --git a/src/lib/Bcfg2/Client/Frame.py b/src/lib/Bcfg2/Client/Frame.py index 64460ea66..53180ab68 100644 --- a/src/lib/Bcfg2/Client/Frame.py +++ b/src/lib/Bcfg2/Client/Frame.py @@ -1,8 +1,10 @@ """ Frame is the Client Framework that verifies and installs entries, and generates statistics. """ +import os import sys import time +import select import fnmatch import logging import Bcfg2.Client.Tools @@ -160,6 +162,9 @@ class Frame(object): iprompt = entry.get('qtext') else: iprompt = prompt % (entry.tag, entry.get('name')) + # flush input buffer + while len(select.select([sys.stdin.fileno()], [], [], 0.0)[0]) > 0: + os.read(sys.stdin.fileno(), 4096) try: ans = input(iprompt.encode(sys.stdout.encoding, 'replace')) if ans in ['y', 'Y']: diff --git a/src/lib/Bcfg2/Client/Tools/Action.py b/src/lib/Bcfg2/Client/Tools/Action.py index 7726da94c..b1a897c81 100644 --- a/src/lib/Bcfg2/Client/Tools/Action.py +++ b/src/lib/Bcfg2/Client/Tools/Action.py @@ -1,5 +1,8 @@ """Action driver""" +import os +import sys +import select import Bcfg2.Client.Tools from Bcfg2.Client.Frame import matches_white_list, passes_black_list from Bcfg2.Compat import input # pylint: disable=W0622 @@ -33,6 +36,10 @@ class Action(Bcfg2.Client.Tools.Tool): if self.setup['interactive']: prompt = ('Run Action %s, %s: (y/N): ' % (entry.get('name'), entry.get('command'))) + # flush input buffer + while len(select.select([sys.stdin.fileno()], [], [], + 0.0)[0]) > 0: + os.read(sys.stdin.fileno(), 4096) ans = input(prompt) if ans not in ['y', 'Y']: return False diff --git a/src/lib/Bcfg2/Client/Tools/__init__.py b/src/lib/Bcfg2/Client/Tools/__init__.py index 4022692be..927b25ba8 100644 --- a/src/lib/Bcfg2/Client/Tools/__init__.py +++ b/src/lib/Bcfg2/Client/Tools/__init__.py @@ -1,7 +1,9 @@ """This contains all Bcfg2 Tool modules""" import os +import sys import stat +import select from subprocess import Popen, PIPE import Bcfg2.Client.XML from Bcfg2.Compat import input, walk_packages # pylint: disable=W0622 @@ -373,6 +375,10 @@ class SvcTool(Tool): if self.setup['interactive']: prompt = ('Restart service %s?: (y/N): ' % entry.get('name')) + # flush input buffer + while len(select.select([sys.stdin.fileno()], [], [], + 0.0)[0]) > 0: + os.read(sys.stdin.fileno(), 4096) ans = input(prompt) if ans not in ['y', 'Y']: continue diff --git a/src/lib/Bcfg2/Server/Admin/Init.py b/src/lib/Bcfg2/Server/Admin/Init.py index 869dc1aca..14065980d 100644 --- a/src/lib/Bcfg2/Server/Admin/Init.py +++ b/src/lib/Bcfg2/Server/Admin/Init.py @@ -1,11 +1,13 @@ """ Interactively initialize a new repository. """ -import getpass + import os +import sys +import stat +import select import random import socket -import stat import string -import sys +import getpass import subprocess import Bcfg2.Server.Admin @@ -85,6 +87,14 @@ OS_LIST = [('Red Hat/Fedora/RHEL/RHAS/Centos', 'redhat'), ('Arch', 'arch')] +def safe_input(prompt): + """ input() that flushes the input buffer before accepting input """ + # flush input buffer + while len(select.select([sys.stdin.fileno()], [], [], 0.0)[0]) > 0: + os.read(sys.stdin.fileno(), 4096) + return input(prompt) + + def gen_password(length): """Generates a random alphanumeric password with length characters.""" chars = string.letters + string.digits @@ -116,8 +126,8 @@ def create_conf(confpath, confdata): """ create the config file """ # Don't overwrite existing bcfg2.conf file if os.path.exists(confpath): - result = input("\nWarning: %s already exists. " - "Overwrite? [y/N]: " % confpath) + result = safe_input("\nWarning: %s already exists. " + "Overwrite? [y/N]: " % confpath) if result not in ['Y', 'y']: print("Leaving %s unchanged" % confpath) return @@ -186,8 +196,8 @@ class Init(Bcfg2.Server.Admin.Mode): def _prompt_hostname(self): """Ask for the server hostname.""" - data = input("What is the server's hostname [%s]: " % - socket.getfqdn()) + data = safe_input("What is the server's hostname [%s]: " % + socket.getfqdn()) if data != '': self.data['shostname'] = data else: @@ -195,21 +205,21 @@ class Init(Bcfg2.Server.Admin.Mode): def _prompt_config(self): """Ask for the configuration file path.""" - newconfig = input("Store Bcfg2 configuration in [%s]: " % - self.configfile) + newconfig = safe_input("Store Bcfg2 configuration in [%s]: " % + self.configfile) if newconfig != '': self.data['configfile'] = os.path.abspath(newconfig) def _prompt_repopath(self): """Ask for the repository path.""" while True: - newrepo = input("Location of Bcfg2 repository [%s]: " % + newrepo = safe_input("Location of Bcfg2 repository [%s]: " % self.data['repopath']) if newrepo != '': self.data['repopath'] = os.path.abspath(newrepo) if os.path.isdir(self.data['repopath']): - response = input("Directory %s exists. Overwrite? [y/N]:" % - self.data['repopath']) + response = safe_input("Directory %s exists. Overwrite? [y/N]:" + % self.data['repopath']) if response.lower().strip() == 'y': break else: @@ -225,8 +235,8 @@ class Init(Bcfg2.Server.Admin.Mode): def _prompt_server(self): """Ask for the server name.""" - newserver = input("Input the server location [%s]: " % - self.data['server_uri']) + newserver = safe_input("Input the server location [%s]: " % + self.data['server_uri']) if newserver != '': self.data['server_uri'] = newserver @@ -238,7 +248,7 @@ class Init(Bcfg2.Server.Admin.Mode): prompt += ': ' while True: try: - osidx = int(input(prompt)) + osidx = int(safe_input(prompt)) self.data['os_sel'] = OS_LIST[osidx - 1][1] break except ValueError: @@ -248,27 +258,28 @@ class Init(Bcfg2.Server.Admin.Mode): """Ask for the key details (country, state, and location).""" print("The following questions affect SSL certificate generation.") print("If no data is provided, the default values are used.") - newcountry = input("Country name (2 letter code) for certificate: ") + newcountry = safe_input("Country name (2 letter code) for " + "certificate: ") if newcountry != '': if len(newcountry) == 2: self.data['country'] = newcountry else: while len(newcountry) != 2: - newcountry = input("2 letter country code (eg. US): ") + newcountry = safe_input("2 letter country code (eg. US): ") if len(newcountry) == 2: self.data['country'] = newcountry break else: self.data['country'] = 'US' - newstate = input("State or Province Name (full name) for " - "certificate: ") + newstate = safe_input("State or Province Name (full name) for " + "certificate: ") if newstate != '': self.data['state'] = newstate else: self.data['state'] = 'Illinois' - newlocation = input("Locality Name (eg, city) for certificate: ") + newlocation = safe_input("Locality Name (eg, city) for certificate: ") if newlocation != '': self.data['location'] = newlocation else: @@ -277,12 +288,12 @@ class Init(Bcfg2.Server.Admin.Mode): def _prompt_keypath(self): """ Ask for the key pair location. Try to use sensible defaults depending on the OS """ - keypath = input("Path where Bcfg2 server private key will be created " - "[%s]: " % self.data['keypath']) + keypath = safe_input("Path where Bcfg2 server private key will be " + "created [%s]: " % self.data['keypath']) if keypath: self.data['keypath'] = keypath - certpath = input("Path where Bcfg2 server cert will be created" - "[%s]: " % self.data['certpath']) + certpath = safe_input("Path where Bcfg2 server cert will be created" + "[%s]: " % self.data['certpath']) if certpath: self.data['certpath'] = certpath diff --git a/src/lib/Bcfg2/Server/Admin/Pull.py b/src/lib/Bcfg2/Server/Admin/Pull.py index e41652205..130e85b67 100644 --- a/src/lib/Bcfg2/Server/Admin/Pull.py +++ b/src/lib/Bcfg2/Server/Admin/Pull.py @@ -1,8 +1,10 @@ """ Retrieves entries from clients and integrates the information into the repository """ -import getopt +import os import sys +import getopt +import select import Bcfg2.Server.Admin from Bcfg2.Compat import input # pylint: disable=W0622 @@ -99,6 +101,10 @@ class Pull(Bcfg2.Server.Admin.MetadataCore): else: print(" => host entry: %s" % (choice.hostname)) + # flush input buffer + while len(select.select([sys.stdin.fileno()], [], [], + 0.0)[0]) > 0: + os.read(sys.stdin.fileno(), 4096) ans = input("Use this entry? [yN]: ") in ['y', 'Y'] if ans: return choice diff --git a/src/sbin/bcfg2-crypt b/src/sbin/bcfg2-crypt index 0693b430c..961a8dc58 100755 --- a/src/sbin/bcfg2-crypt +++ b/src/sbin/bcfg2-crypt @@ -4,6 +4,7 @@ import os import sys import copy +import select import logging import lxml.etree import Bcfg2.Logger @@ -31,7 +32,7 @@ class Encryptor(object): self.passphrase = None self.pname = None self.logger = logging.getLogger(self.__class__.__name__) - + def get_encrypted_filename(self, plaintext_filename): """ get the name of the file encrypted data should be written to """ return plaintext_filename @@ -67,7 +68,7 @@ class Encryptor(object): if self.setup['passphrase']: self.pname = self.setup['passphrase'] - + if self.pname: if self.setup.cfp.has_option("encryption", self.pname): self.passphrase = self.setup.cfp.get("encryption", @@ -182,7 +183,7 @@ class Encryptor(object): self.logger.error("Error getting encrypted data from %s: %s" % (fname, err)) return False - + try: return self.unchunk(plaintext, crypted) except EncryptionChunkingError: @@ -317,10 +318,14 @@ class PropertiesEncryptor(Encryptor): print(lxml.etree.tostring( elt, xml_declaration=False).decode("UTF-8").strip()) + # flush input buffer + while len(select.select([sys.stdin.fileno()], [], [], + 0.0)[0]) > 0: + os.read(sys.stdin.fileno(), 4096) ans = input("Encrypt this element? [y/N] ") if not ans.lower().startswith("y"): elements.remove(element) - + # this is not a good use of a generator, but we need to # generate the full list of elements in order to ensure that # some exist before we know what to return @@ -386,11 +391,11 @@ def main(): # pylint: disable=R0912,R0915 elif setup['interactive']: logger.error("Cannot decrypt interactively") setup['interactive'] = False - + if setup['cfg']: if setup['properties']: logger.error("You cannot specify both --cfg and --properties") - raise SystemExit(1) + raise SystemExit(1) if setup['xpath']: logger.error("Specifying --xpath with --cfg is nonsensical, " "ignoring --xpath") @@ -411,7 +416,7 @@ def main(): # pylint: disable=R0912,R0915 if not os.path.exists(fname): logger.error("%s does not exist, skipping" % fname) continue - + # figure out if we need to encrypt this as a Properties file # or as a Cfg file props = False -- cgit v1.2.3-1-g7c22 From e110656667f96b6beb7e7b5a2407316678669bcc Mon Sep 17 00:00:00 2001 From: Sol Jerome Date: Mon, 12 Nov 2012 12:21:09 -0600 Subject: SELinux: Fix string -> int conversion Signed-off-by: Sol Jerome --- src/lib/Bcfg2/Client/Tools/SELinux.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/lib/Bcfg2/Client/Tools/SELinux.py b/src/lib/Bcfg2/Client/Tools/SELinux.py index 5ac96f999..fc47883c9 100644 --- a/src/lib/Bcfg2/Client/Tools/SELinux.py +++ b/src/lib/Bcfg2/Client/Tools/SELinux.py @@ -41,7 +41,7 @@ def netmask_itoa(netmask, proto="ipv4"): size = 128 family = socket.AF_INET6 try: - int(netmask) + netmask = int(netmask) except ValueError: return netmask -- cgit v1.2.3-1-g7c22 From 1afd6b3c9edcf4f30af95fa4504b5da45509828f Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Tue, 13 Nov 2012 07:30:17 -0500 Subject: allow setting NagiosGen Options while using the default client settings (from Marc Gariepy) --- src/lib/Bcfg2/Server/Plugins/NagiosGen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/lib/Bcfg2/Server/Plugins/NagiosGen.py b/src/lib/Bcfg2/Server/Plugins/NagiosGen.py index fbad0a37b..023547b7e 100644 --- a/src/lib/Bcfg2/Server/Plugins/NagiosGen.py +++ b/src/lib/Bcfg2/Server/Plugins/NagiosGen.py @@ -81,7 +81,7 @@ class NagiosGen(Bcfg2.Server.Plugin.Plugin, if xtra: host_config.extend([self.line_fmt % (opt, val) for opt, val in list(xtra.items())]) - else: + if 'use' not in xtra: host_config.append(self.line_fmt % ('use', 'default')) host_config.append('}') -- cgit v1.2.3-1-g7c22 From 1ff2dc519f00a942b14e8a157762aa990606f8f3 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Tue, 13 Nov 2012 07:30:53 -0500 Subject: SSHbase: improved error message --- src/lib/Bcfg2/Server/Plugins/SSHbase.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/lib/Bcfg2/Server/Plugins/SSHbase.py b/src/lib/Bcfg2/Server/Plugins/SSHbase.py index bab7c4a4a..ff569334d 100644 --- a/src/lib/Bcfg2/Server/Plugins/SSHbase.py +++ b/src/lib/Bcfg2/Server/Plugins/SSHbase.py @@ -365,8 +365,9 @@ class SSHbase(Bcfg2.Server.Plugin.Plugin, is_bound = False while not is_bound: if tries >= 10: - self.logger.error("%s still not registered" % filename) - raise Bcfg2.Server.Plugin.PluginExecutionError + msg = "%s still not registered" % filename + self.logger.error(msg) + raise Bcfg2.Server.Plugin.PluginExecutionError(msg) self.core.fam.handle_events_in_interval(1) tries += 1 try: -- cgit v1.2.3-1-g7c22 From 5a6782cf7191a201787da9401f5d61a63255ab09 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Tue, 13 Nov 2012 11:07:19 -0500 Subject: SSHbase: fixed invalidation of ssh_known_hosts cache --- src/lib/Bcfg2/Server/Plugins/SSHbase.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/lib/Bcfg2/Server/Plugins/SSHbase.py b/src/lib/Bcfg2/Server/Plugins/SSHbase.py index ff569334d..4d2529ed6 100644 --- a/src/lib/Bcfg2/Server/Plugins/SSHbase.py +++ b/src/lib/Bcfg2/Server/Plugins/SSHbase.py @@ -9,7 +9,7 @@ import logging import tempfile from subprocess import Popen, PIPE import Bcfg2.Server.Plugin -from Bcfg2.Compat import u_str, reduce, b64encode # pylint: disable=W0622 +from Bcfg2.Compat import any, u_str, reduce, b64encode # pylint: disable=W0622 LOGGER = logging.getLogger(__name__) @@ -111,9 +111,7 @@ class SSHbase(Bcfg2.Server.Plugin.Plugin, is regenerated each time a new key is generated. """ - name = 'SSHbase' __author__ = 'bcfg-dev@mcs.anl.gov' - keypatterns = ["ssh_host_dsa_key", "ssh_host_ecdsa_key", "ssh_host_rsa_key", @@ -250,7 +248,9 @@ class SSHbase(Bcfg2.Server.Plugin.Plugin, for entry in list(self.entries.values()): if entry.specific.match(event.filename): entry.handle_event(event) - if event.filename.endswith(".pub"): + if any(event.filename.startswith(kp) + for kp in self.keypatterns + if kp.endswith(".pub")): self.logger.info("New public key %s; invalidating " "ssh_known_hosts cache" % event.filename) self.skn = False -- cgit v1.2.3-1-g7c22 From 3b3fb259e81398ecfa838ed622f70e685f9eaaa7 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Tue, 13 Nov 2012 11:41:42 -0500 Subject: fixed some docs for sphinx 1.1 --- src/lib/Bcfg2/Server/Plugins/Packages/PackagesSources.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/PackagesSources.py b/src/lib/Bcfg2/Server/Plugins/Packages/PackagesSources.py index 94dc6d2fd..2c3ac2096 100644 --- a/src/lib/Bcfg2/Server/Plugins/Packages/PackagesSources.py +++ b/src/lib/Bcfg2/Server/Plugins/Packages/PackagesSources.py @@ -121,8 +121,8 @@ class PackagesSources(Bcfg2.Server.Plugin.StructFile, self.entries.append(source) Index.__doc__ = Bcfg2.Server.Plugin.StructFile.Index.__doc__ + """ -``Index`` is responsible for calling :func:`source_from_xml` for each -``Source`` tag in each file. """ + ``Index`` is responsible for calling :func:`source_from_xml` + for each ``Source`` tag in each file. """ @Bcfg2.Server.Plugin.track_statistics() def source_from_xml(self, xsource): -- cgit v1.2.3-1-g7c22 From c767963bb758b50c7010bf2249221c72c95b8857 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Tue, 13 Nov 2012 13:17:11 -0500 Subject: Cfg: prevent genshi loader from caching templates --- src/lib/Bcfg2/Server/Plugins/Cfg/CfgGenshiGenerator.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'src') diff --git a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgGenshiGenerator.py b/src/lib/Bcfg2/Server/Plugins/Cfg/CfgGenshiGenerator.py index ce77717da..cfb978c42 100644 --- a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgGenshiGenerator.py +++ b/src/lib/Bcfg2/Server/Plugins/Cfg/CfgGenshiGenerator.py @@ -70,8 +70,8 @@ class CfgGenshiGenerator(CfgGenerator): msg = "Cfg: Genshi is not available: %s" % fname LOGGER.error(msg) raise Bcfg2.Server.Plugin.PluginExecutionError(msg) - self.loader = self.__loader_cls__() self.template = None + self.loader = self.__loader_cls__(max_cache_size=0) __init__.__doc__ = CfgGenerator.__init__.__doc__ def get_data(self, entry, metadata): @@ -146,9 +146,6 @@ class CfgGenshiGenerator(CfgGenerator): raise def handle_event(self, event): - CfgGenerator.handle_event(self, event) - if self.data is None: - return try: self.template = self.loader.load(self.name, cls=NewTextTemplate, encoding=self.encoding) -- cgit v1.2.3-1-g7c22 From 0ccb4cd10b38362ec61da22238b37b3a55adc7fb Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Tue, 13 Nov 2012 14:50:12 -0500 Subject: don't pass full stack traces to client on bind failure --- src/lib/Bcfg2/Server/Core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/lib/Bcfg2/Server/Core.py b/src/lib/Bcfg2/Server/Core.py index a5fda6f0d..cd2aa949f 100644 --- a/src/lib/Bcfg2/Server/Core.py +++ b/src/lib/Bcfg2/Server/Core.py @@ -516,7 +516,7 @@ class BaseCore(object): except PluginExecutionError: exc = sys.exc_info()[1] if 'failure' not in entry.attrib: - entry.set('failure', 'bind error: %s' % format_exc()) + entry.set('failure', 'bind error: %s' % exc) self.logger.error("Failed to bind entry %s:%s: %s" % (entry.tag, entry.get('name'), exc)) except Exception: -- cgit v1.2.3-1-g7c22 From 5fc9984ce584b9f0a0982f4d5ce958cac8df9128 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Tue, 13 Nov 2012 16:36:21 -0500 Subject: fixed client lock check --- src/lib/Bcfg2/Client/Client.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/lib/Bcfg2/Client/Client.py b/src/lib/Bcfg2/Client/Client.py index 0400e3ff7..636aa5177 100644 --- a/src/lib/Bcfg2/Client/Client.py +++ b/src/lib/Bcfg2/Client/Client.py @@ -106,7 +106,9 @@ class Client(object): self.logger.info(ret.text) finally: os.unlink(scriptname) - except: # pylint: disable=W0702 + except SystemExit: + raise + except: self._probe_failure(name, sys.exc_info()[1]) return ret @@ -258,8 +260,7 @@ class Client(object): except Bcfg2.Client.XML.ParseError: syntax_error = sys.exc_info()[1] self.fatal_error("The configuration could not be parsed: %s" % - (syntax_error)) - return(1) + syntax_error) times['config_parse'] = time.time() @@ -296,10 +297,13 @@ class Client(object): "If you what to bypass the check, run " "with %s option" % Bcfg2.Options.OMIT_LOCK_CHECK.cmd) - except: # pylint: disable=W0702 + except SystemExit: + raise + except: lockfile = None self.logger.error("Failed to open lockfile") - # execute the said configuration + + # execute the configuration self.tools.Execute() if not self.setup['omit_lock_check']: -- cgit v1.2.3-1-g7c22 From ee16ced43e5050455368bb794e1fdfbba8eaa9f0 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Tue, 13 Nov 2012 16:50:45 -0500 Subject: SSHbase: improved error messages --- src/lib/Bcfg2/Server/Plugins/SSHbase.py | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/lib/Bcfg2/Server/Plugins/SSHbase.py b/src/lib/Bcfg2/Server/Plugins/SSHbase.py index 4d2529ed6..53b76735f 100644 --- a/src/lib/Bcfg2/Server/Plugins/SSHbase.py +++ b/src/lib/Bcfg2/Server/Plugins/SSHbase.py @@ -9,6 +9,7 @@ import logging import tempfile from subprocess import Popen, PIPE import Bcfg2.Server.Plugin +from Bcfg2.Server.Plugin import PluginExecutionError from Bcfg2.Compat import any, u_str, reduce, b64encode # pylint: disable=W0622 LOGGER = logging.getLogger(__name__) @@ -386,26 +387,30 @@ class SSHbase(Bcfg2.Server.Plugin.Plugin, else: keytype = 'rsa1' else: - self.logger.error("Unknown key filename: %s" % filename) - return + raise PluginExecutionError("Unknown key filename: %s" % filename) - fileloc = "%s/%s" % (self.data, hostkey) - publoc = self.data + '/' + ".".join([hostkey.split('.')[0], 'pub', - "H_%s" % client]) + fileloc = os.path.join(self.data, hostkey) + publoc = os.path.join(self.data, + ".".join([hostkey.split('.')[0], 'pub', + "H_%s" % client])) tempdir = tempfile.mkdtemp() - temploc = "%s/%s" % (tempdir, hostkey) + temploc = os.path.join(tempdir, hostkey) cmd = ["ssh-keygen", "-q", "-f", temploc, "-N", "", "-t", keytype, "-C", "root@%s" % client] + self.debug_log("SSHbase: Running: %s" % " ".join(cmd)) proc = Popen(cmd, stdout=PIPE, stdin=PIPE) - proc.communicate() - proc.wait() + err = proc.communicate()[1] + if proc.wait(): + raise PluginExecutionError("SSHbase: Error running ssh-keygen: %s" + % err) try: shutil.copy(temploc, fileloc) shutil.copy("%s.pub" % temploc, publoc) except IOError: err = sys.exc_info()[1] - self.logger.error("Temporary SSH keys not found: %s" % err) + raise PluginExecutionError("Temporary SSH keys not found: %s" % + err) try: os.unlink(temploc) @@ -413,7 +418,8 @@ class SSHbase(Bcfg2.Server.Plugin.Plugin, os.rmdir(tempdir) except OSError: err = sys.exc_info()[1] - self.logger.error("Failed to unlink temporary ssh keys: %s" % err) + raise PluginExecutionError("Failed to unlink temporary ssh keys: " + "%s" % err) def AcceptChoices(self, _, metadata): return [Bcfg2.Server.Plugin.Specificity(hostname=metadata.hostname)] @@ -421,8 +427,9 @@ class SSHbase(Bcfg2.Server.Plugin.Plugin, def AcceptPullData(self, specific, entry, log): """Per-plugin bcfg2-admin pull support.""" # specific will always be host specific - filename = "%s/%s.H_%s" % (self.data, entry['name'].split('/')[-1], - specific.hostname) + filename = os.path.join(self.data, + "%s.H_%s" % (entry['name'].split('/')[-1], + specific.hostname)) try: open(filename, 'w').write(entry['text']) if log: -- cgit v1.2.3-1-g7c22 From 3787db7a50f70e1c8cb575546949f32c2958fe20 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Tue, 13 Nov 2012 17:04:42 -0500 Subject: Cfg: improved error messages --- .../Server/Plugins/Cfg/CfgCheetahGenerator.py | 9 ++----- src/lib/Bcfg2/Server/Plugins/Cfg/CfgDiffFilter.py | 10 +++---- .../Server/Plugins/Cfg/CfgEncryptedGenerator.py | 7 +---- .../Plugins/Cfg/CfgEncryptedGenshiGenerator.py | 9 +------ .../Plugins/Cfg/CfgExternalCommandVerifier.py | 10 ++----- .../Bcfg2/Server/Plugins/Cfg/CfgGenshiGenerator.py | 31 +++++++++------------- src/lib/Bcfg2/Server/Plugins/Cfg/CfgInfoXML.py | 12 +++------ src/lib/Bcfg2/Server/Plugins/Cfg/__init__.py | 4 +-- 8 files changed, 27 insertions(+), 65 deletions(-) (limited to 'src') diff --git a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgCheetahGenerator.py b/src/lib/Bcfg2/Server/Plugins/Cfg/CfgCheetahGenerator.py index 73c70901b..8ebd8d921 100644 --- a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgCheetahGenerator.py +++ b/src/lib/Bcfg2/Server/Plugins/Cfg/CfgCheetahGenerator.py @@ -2,12 +2,9 @@ `_ templating system to generate :ref:`server-plugins-generators-cfg` files. """ -import logging -import Bcfg2.Server.Plugin +from Bcfg2.Server.Plugin import PluginExecutionError from Bcfg2.Server.Plugins.Cfg import CfgGenerator -LOGGER = logging.getLogger(__name__) - try: from Cheetah.Template import Template HAS_CHEETAH = True @@ -33,9 +30,7 @@ class CfgCheetahGenerator(CfgGenerator): def __init__(self, fname, spec, encoding): CfgGenerator.__init__(self, fname, spec, encoding) if not HAS_CHEETAH: - msg = "Cfg: Cheetah is not available: %s" % self.name - LOGGER.error(msg) - raise Bcfg2.Server.Plugin.PluginExecutionError(msg) + raise PluginExecutionError("Cheetah is not available") __init__.__doc__ = CfgGenerator.__init__.__doc__ def get_data(self, entry, metadata): diff --git a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgDiffFilter.py b/src/lib/Bcfg2/Server/Plugins/Cfg/CfgDiffFilter.py index 00b95c970..da506a195 100644 --- a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgDiffFilter.py +++ b/src/lib/Bcfg2/Server/Plugins/Cfg/CfgDiffFilter.py @@ -1,14 +1,11 @@ """ Handle .diff files, which apply diffs to plaintext files """ import os -import logging import tempfile -import Bcfg2.Server.Plugin +from Bcfg2.Server.Plugin import PluginExecutionError from subprocess import Popen, PIPE from Bcfg2.Server.Plugins.Cfg import CfgFilter -LOGGER = logging.getLogger(__name__) - class CfgDiffFilter(CfgFilter): """ CfgDiffFilter applies diffs to plaintext @@ -32,8 +29,7 @@ class CfgDiffFilter(CfgFilter): output = open(basename, 'r').read() os.unlink(basename) if ret != 0: - msg = "Error applying diff %s: %s" % (self.name, stderr) - LOGGER.error(msg) - raise Bcfg2.Server.Plugin.PluginExecutionError(msg) + raise PluginExecutionError("Error applying diff %s: %s" % + (self.name, stderr)) return output modify_data.__doc__ = CfgFilter.modify_data.__doc__ diff --git a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgEncryptedGenerator.py b/src/lib/Bcfg2/Server/Plugins/Cfg/CfgEncryptedGenerator.py index 26faf6e2c..3b4703ddb 100644 --- a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgEncryptedGenerator.py +++ b/src/lib/Bcfg2/Server/Plugins/Cfg/CfgEncryptedGenerator.py @@ -1,7 +1,6 @@ """ CfgEncryptedGenerator lets you encrypt your plaintext :ref:`server-plugins-generators-cfg` files on the server. """ -import logging from Bcfg2.Server.Plugin import PluginExecutionError from Bcfg2.Server.Plugins.Cfg import CfgGenerator, SETUP try: @@ -11,8 +10,6 @@ try: except ImportError: HAS_CRYPTO = False -LOGGER = logging.getLogger(__name__) - class CfgEncryptedGenerator(CfgGenerator): """ CfgEncryptedGenerator lets you encrypt your plaintext @@ -28,9 +25,7 @@ class CfgEncryptedGenerator(CfgGenerator): def __init__(self, fname, spec, encoding): CfgGenerator.__init__(self, fname, spec, encoding) if not HAS_CRYPTO: - msg = "Cfg: M2Crypto is not available" - LOGGER.error(msg) - raise PluginExecutionError(msg) + raise PluginExecutionError("M2Crypto is not available") __init__.__doc__ = CfgGenerator.__init__.__doc__ def handle_event(self, event): diff --git a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgEncryptedGenshiGenerator.py b/src/lib/Bcfg2/Server/Plugins/Cfg/CfgEncryptedGenshiGenerator.py index feedbdb1b..130652aef 100644 --- a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgEncryptedGenshiGenerator.py +++ b/src/lib/Bcfg2/Server/Plugins/Cfg/CfgEncryptedGenshiGenerator.py @@ -1,7 +1,6 @@ """ Handle encrypted Genshi templates (.crypt.genshi or .genshi.crypt files) """ -import logging from Bcfg2.Compat import StringIO from Bcfg2.Server.Plugin import PluginExecutionError from Bcfg2.Server.Plugins.Cfg import SETUP @@ -19,10 +18,6 @@ except ImportError: # CfgGenshiGenerator will raise errors if genshi doesn't exist TemplateLoader = object # pylint: disable=C0103 -LOGGER = logging.getLogger(__name__) - -LOGGER = logging.getLogger(__name__) - class EncryptedTemplateLoader(TemplateLoader): """ Subclass :class:`genshi.template.TemplateLoader` to decrypt @@ -53,6 +48,4 @@ class CfgEncryptedGenshiGenerator(CfgGenshiGenerator): def __init__(self, fname, spec, encoding): CfgGenshiGenerator.__init__(self, fname, spec, encoding) if not HAS_CRYPTO: - msg = "Cfg: M2Crypto is not available" - LOGGER.error(msg) - raise PluginExecutionError(msg) + raise PluginExecutionError("M2Crypto is not available") diff --git a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgExternalCommandVerifier.py b/src/lib/Bcfg2/Server/Plugins/Cfg/CfgExternalCommandVerifier.py index 023af7d4e..b702ac899 100644 --- a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgExternalCommandVerifier.py +++ b/src/lib/Bcfg2/Server/Plugins/Cfg/CfgExternalCommandVerifier.py @@ -3,13 +3,10 @@ import os import sys import shlex -import logging -import Bcfg2.Server.Plugin +from Bcfg2.Server.Plugin import PluginExecutionError from subprocess import Popen, PIPE from Bcfg2.Server.Plugins.Cfg import CfgVerifier, CfgVerificationError -LOGGER = logging.getLogger(__name__) - class CfgExternalCommandVerifier(CfgVerifier): """ Invoke an external script to verify @@ -46,9 +43,6 @@ class CfgExternalCommandVerifier(CfgVerifier): if bangpath.startswith("#!"): self.cmd.extend(shlex.split(bangpath[2:].strip())) else: - msg = "%s: Cannot execute %s" % (self.__class__.__name__, - self.name) - LOGGER.error(msg) - raise Bcfg2.Server.Plugin.PluginExecutionError(msg) + raise PluginExecutionError("Cannot execute %s" % self.name) self.cmd.append(self.name) handle_event.__doc__ = CfgVerifier.handle_event.__doc__ diff --git a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgGenshiGenerator.py b/src/lib/Bcfg2/Server/Plugins/Cfg/CfgGenshiGenerator.py index cfb978c42..df0c30c09 100644 --- a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgGenshiGenerator.py +++ b/src/lib/Bcfg2/Server/Plugins/Cfg/CfgGenshiGenerator.py @@ -4,13 +4,10 @@ import re import sys -import logging import traceback -import Bcfg2.Server.Plugin +from Bcfg2.Server.Plugin import PluginExecutionError from Bcfg2.Server.Plugins.Cfg import CfgGenerator -LOGGER = logging.getLogger(__name__) - try: import genshi.core from genshi.template import TemplateLoader, NewTextTemplate @@ -67,9 +64,7 @@ class CfgGenshiGenerator(CfgGenerator): def __init__(self, fname, spec, encoding): CfgGenerator.__init__(self, fname, spec, encoding) if not HAS_GENSHI: - msg = "Cfg: Genshi is not available: %s" % fname - LOGGER.error(msg) - raise Bcfg2.Server.Plugin.PluginExecutionError(msg) + raise PluginExecutionError("Genshi is not available") self.template = None self.loader = self.__loader_cls__(max_cache_size=0) __init__.__doc__ = CfgGenerator.__init__.__doc__ @@ -92,15 +87,15 @@ class CfgGenshiGenerator(CfgGenerator): stack = traceback.extract_tb(sys.exc_info()[2]) for quad in stack: if quad[0] == self.name: - LOGGER.error("Cfg: Error rendering %s at '%s': %s: %s" % - (fname, quad[2], err.__class__.__name__, err)) - break + raise PluginExecutionError("%s: %s at '%s'" % + (err.__class__.__name__, err, + quad[2])) raise except: - self._handle_genshi_exception(fname, sys.exc_info()) + self._handle_genshi_exception(sys.exc_info()) get_data.__doc__ = CfgGenerator.get_data.__doc__ - def _handle_genshi_exception(self, fname, exc): + def _handle_genshi_exception(self, exc): """ this is horrible, and I deeply apologize to whoever gets to maintain this after I go to the Great Beer Garden in the Sky. genshi is incredibly opaque about what's being executed, @@ -140,9 +135,9 @@ class CfgGenshiGenerator(CfgGenerator): # single line break) real_lineno = lineno - contents.code.co_firstlineno src = re.sub(r'\n\n+', '\n', contents.source).splitlines() - LOGGER.error("Cfg: Error rendering %s at '%s': %s: %s" % - (fname, src[real_lineno], err.__class__.__name__, - err)) + raise PluginExecutionError("%s: %s at '%s'" % + (err.__class__.__name__, err, + src[real_lineno])) raise def handle_event(self, event): @@ -150,8 +145,6 @@ class CfgGenshiGenerator(CfgGenerator): self.template = self.loader.load(self.name, cls=NewTextTemplate, encoding=self.encoding) except: - msg = "Cfg: Could not load template %s: %s" % (self.name, - sys.exc_info()[1]) - LOGGER.error(msg) - raise Bcfg2.Server.Plugin.PluginExecutionError(msg) + raise PluginExecutionError("Failed to load template: %s" % + sys.exc_info()[1]) handle_event.__doc__ = CfgGenerator.handle_event.__doc__ diff --git a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgInfoXML.py b/src/lib/Bcfg2/Server/Plugins/Cfg/CfgInfoXML.py index e5ba0a51b..3b6fc8fa0 100644 --- a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgInfoXML.py +++ b/src/lib/Bcfg2/Server/Plugins/Cfg/CfgInfoXML.py @@ -1,11 +1,8 @@ """ Handle info.xml files """ -import logging -import Bcfg2.Server.Plugin +from Bcfg2.Server.Plugin import PluginExecutionError, InfoXML from Bcfg2.Server.Plugins.Cfg import CfgInfo -LOGGER = logging.getLogger(__name__) - class CfgInfoXML(CfgInfo): """ CfgInfoXML handles :file:`info.xml` files for @@ -16,16 +13,15 @@ class CfgInfoXML(CfgInfo): def __init__(self, path): CfgInfo.__init__(self, path) - self.infoxml = Bcfg2.Server.Plugin.InfoXML(path) + self.infoxml = InfoXML(path) __init__.__doc__ = CfgInfo.__init__.__doc__ def bind_info_to_entry(self, entry, metadata): mdata = dict() self.infoxml.pnode.Match(metadata, mdata, entry=entry) if 'Info' not in mdata: - msg = "Failed to set metadata for file %s" % entry.get('name') - LOGGER.error(msg) - raise Bcfg2.Server.Plugin.PluginExecutionError(msg) + raise PluginExecutionError("Failed to set metadata for file %s" % + entry.get('name')) self._set_info(entry, mdata['Info'][None]) bind_info_to_entry.__doc__ = CfgInfo.bind_info_to_entry.__doc__ diff --git a/src/lib/Bcfg2/Server/Plugins/Cfg/__init__.py b/src/lib/Bcfg2/Server/Plugins/Cfg/__init__.py index 58f6e1e42..db6810e7c 100644 --- a/src/lib/Bcfg2/Server/Plugins/Cfg/__init__.py +++ b/src/lib/Bcfg2/Server/Plugins/Cfg/__init__.py @@ -542,8 +542,8 @@ class CfgEntrySet(Bcfg2.Server.Plugin.EntrySet): try: return generator.get_data(entry, metadata) except: - msg = "Cfg: exception rendering %s with %s: %s" % \ - (entry.get("name"), generator, sys.exc_info()[1]) + msg = "Cfg: Error rendering %s: %s" % (entry.get("name"), + sys.exc_info()[1]) LOGGER.error(msg) raise Bcfg2.Server.Plugin.PluginExecutionError(msg) -- cgit v1.2.3-1-g7c22 From 2fecc7a73e658f3977e0351f900694a68f404db3 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Wed, 14 Nov 2012 10:25:51 -0500 Subject: fixed typos in error message --- src/lib/Bcfg2/Client/Client.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/lib/Bcfg2/Client/Client.py b/src/lib/Bcfg2/Client/Client.py index 636aa5177..f197a9074 100644 --- a/src/lib/Bcfg2/Client/Client.py +++ b/src/lib/Bcfg2/Client/Client.py @@ -293,9 +293,9 @@ class Client(object): fcntl.LOCK_EX | fcntl.LOCK_NB) except IOError: # otherwise exit and give a warning to the user - self.fatal_error("An other instance of Bcfg2 is running. " - "If you what to bypass the check, run " - "with %s option" % + self.fatal_error("Another instance of Bcfg2 is running. " + "If you want to bypass the check, run " + "with the %s option" % Bcfg2.Options.OMIT_LOCK_CHECK.cmd) except SystemExit: raise -- cgit v1.2.3-1-g7c22 From 5c0e7644cb666ac499718614f011863e6d84f70b Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Wed, 14 Nov 2012 10:36:53 -0500 Subject: SSLCA: clean up temp files on error, better error messages --- src/lib/Bcfg2/Server/Plugins/SSLCA.py | 74 ++++++++++++++++++++++------------- 1 file changed, 46 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/src/lib/Bcfg2/Server/Plugins/SSLCA.py b/src/lib/Bcfg2/Server/Plugins/SSLCA.py index 2a621eeb0..a920a9cca 100644 --- a/src/lib/Bcfg2/Server/Plugins/SSLCA.py +++ b/src/lib/Bcfg2/Server/Plugins/SSLCA.py @@ -9,6 +9,7 @@ import lxml.etree import tempfile from subprocess import Popen, PIPE, STDOUT from Bcfg2.Compat import ConfigParser, md5 +from Bcfg2.Server.Plugin import PluginExecutionError class SSLCA(Bcfg2.Server.Plugin.GroupSpool): @@ -235,29 +236,37 @@ class SSLCA(Bcfg2.Server.Plugin.GroupSpool): """ creates a new certificate according to the specification """ - req_config = self.build_req_config(entry, metadata) - req = self.build_request(key_filename, req_config, entry) - ca = self.cert_specs[entry.get('name')]['ca'] - ca_config = self.CAs[ca]['config'] - days = self.cert_specs[entry.get('name')]['days'] - passphrase = self.CAs[ca].get('passphrase') - cmd = ["openssl", "ca", "-config", ca_config, "-in", req, - "-days", days, "-batch"] - if passphrase: - cmd.extend(["-passin", "pass:%s" % passphrase]) - self.debug_log("SSLCA: Generating new certificate: %s" % " ".join(cmd)) - proc = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE) - (cert, err) = proc.communicate() - if proc.wait(): - raise Bcfg2.Server.Plugin.PluginExecutionError( - "SSLCA: Failed to generate cert: %s" % - err.splitlines()[-1]) # pylint: disable=E1103 + req_config = None + req = None try: - os.unlink(req_config) - os.unlink(req) - except OSError: - self.logger.error("SSLCA: Failed to unlink temporary files: %s" % - sys.exc_info()[1]) + req_config = self.build_req_config(entry, metadata) + req = self.build_request(key_filename, req_config, entry) + ca = self.cert_specs[entry.get('name')]['ca'] + ca_config = self.CAs[ca]['config'] + days = self.cert_specs[entry.get('name')]['days'] + passphrase = self.CAs[ca].get('passphrase') + cmd = ["openssl", "ca", "-config", ca_config, "-in", req, + "-days", days, "-batch"] + if passphrase: + cmd.extend(["-passin", "pass:%s" % passphrase]) + self.debug_log("SSLCA: Generating new certificate: %s" % + " ".join(cmd)) + proc = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE) + (cert, err) = proc.communicate() + if proc.wait(): + # pylint: disable=E1103 + raise PluginExecutionError("SSLCA: Failed to generate cert: %s" + % err.splitlines()[-1]) + # pylint: enable=E1103 + finally: + try: + if req_config and os.path.exists(req_config): + os.unlink(req_config) + if req and os.path.exists(req): + os.unlink(req) + except OSError: + self.logger.error("SSLCA: Failed to unlink temporary files: %s" + % sys.exc_info()[1]) if (self.cert_specs[entry.get('name')]['append_chain'] and self.CAs[ca]['chaincert']): cert += open(self.CAs[ca]['chaincert']).read() @@ -269,7 +278,7 @@ class SSLCA(Bcfg2.Server.Plugin.GroupSpool): used to generate the required certificate request """ # create temp request config file - conffile = open(tempfile.mkstemp()[1], 'w') + fh, fname = tempfile.mkstemp() cfp = ConfigParser.ConfigParser({}) cfp.optionxform = str defaults = { @@ -301,19 +310,28 @@ class SSLCA(Bcfg2.Server.Plugin.GroupSpool): cfp.set('req_distinguished_name', item, self.cert_specs[entry.get('name')][item]) cfp.set('req_distinguished_name', 'CN', metadata.hostname) - cfp.write(conffile) - conffile.close() - return conffile.name + self.debug_log("SSLCA: Writing temporary request config to %s" % fname) + try: + cfp.write(os.fdopen(fh, 'w')) + except IOError: + raise PluginExecutionError("SSLCA: Failed to write temporary CSR " + "config file: %s" % sys.exc_info()[1]) + return fname def build_request(self, key_filename, req_config, entry): """ creates the certificate request """ - req = tempfile.mkstemp()[1] + fh, req = tempfile.mkstemp() + os.close(fh) days = self.cert_specs[entry.get('name')]['days'] key = self.data + key_filename cmd = ["openssl", "req", "-new", "-config", req_config, "-days", days, "-key", key, "-text", "-out", req] self.debug_log("SSLCA: Generating new CSR: %s" % " ".join(cmd)) - Popen(cmd, stdout=PIPE).wait() + proc = Popen(cmd, stdout=PIPE, stderr=PIPE) + err = proc.communicate()[1] + if proc.wait(): + raise PluginExecutionError("SSLCA: Failed to generate CSR: %s" % + err) return req -- cgit v1.2.3-1-g7c22 From 15e86f26c8781c2a61d241de374e2724761242e1 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Wed, 14 Nov 2012 11:15:49 -0500 Subject: only try to find bcfg2-yum-helper in $PATH once --- src/lib/Bcfg2/Server/Plugins/Packages/Yum.py | 31 ++++++++++++++-------------- 1 file changed, 16 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py b/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py index a7129fc7a..220146100 100644 --- a/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py +++ b/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py @@ -102,6 +102,9 @@ FL = '{http://linux.duke.edu/metadata/filelists}' PULPSERVER = None PULPCONFIG = None +#: The path to bcfg2-yum-helper +HELPER = None + def _setup_pulp(setup): """ Connect to a Pulp server and pass authentication credentials. @@ -308,8 +311,6 @@ class YumCollection(Collection): (certdir, err)) self.pulp_cert_set = PulpCertificateSet(certdir, self.fam) - self._helper = None - @property def __package_groups__(self): """ YumCollections support package groups only if @@ -324,20 +325,20 @@ class YumCollection(Collection): a call to it; I wish there was a way to do this without forking, but apparently not); finally we check in /usr/sbin, the default location. """ - try: - return self.setup.cfp.get("packages:yum", "helper") - except (ConfigParser.NoOptionError, ConfigParser.NoSectionError): - pass - - if not self._helper: - # first see if bcfg2-yum-helper is in PATH + global HELPER + if not HELPER: try: - Popen(['bcfg2-yum-helper'], - stdin=PIPE, stdout=PIPE, stderr=PIPE).wait() - self._helper = 'bcfg2-yum-helper' - except OSError: - self._helper = "/usr/sbin/bcfg2-yum-helper" - return self._helper + HELPER = self.setup.cfp.get("packages:yum", "helper") + except (ConfigParser.NoOptionError, ConfigParser.NoSectionError): + # first see if bcfg2-yum-helper is in PATH + try: + self.debug_log("Checking for bcfg2-yum-helper in $PATH") + Popen(['bcfg2-yum-helper'], + stdin=PIPE, stdout=PIPE, stderr=PIPE).wait() + HELPER = 'bcfg2-yum-helper' + except OSError: + HELPER = "/usr/sbin/bcfg2-yum-helper" + return HELPER @property def use_yum(self): -- cgit v1.2.3-1-g7c22 From 244b31c8a740ee7b1f021bfc03002f1ec572000e Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Wed, 14 Nov 2012 11:16:00 -0500 Subject: SSHbase: turn down the noise --- src/lib/Bcfg2/Server/Plugins/SSHbase.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/lib/Bcfg2/Server/Plugins/SSHbase.py b/src/lib/Bcfg2/Server/Plugins/SSHbase.py index 53b76735f..feb76aa57 100644 --- a/src/lib/Bcfg2/Server/Plugins/SSHbase.py +++ b/src/lib/Bcfg2/Server/Plugins/SSHbase.py @@ -252,8 +252,8 @@ class SSHbase(Bcfg2.Server.Plugin.Plugin, if any(event.filename.startswith(kp) for kp in self.keypatterns if kp.endswith(".pub")): - self.logger.info("New public key %s; invalidating " - "ssh_known_hosts cache" % event.filename) + self.debug_log("New public key %s; invalidating " + "ssh_known_hosts cache" % event.filename) self.skn = False return -- cgit v1.2.3-1-g7c22 From 41f8803559f4d2b9d2df005464c9ad199431f9a6 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Wed, 14 Nov 2012 11:47:14 -0500 Subject: set default umask for server, added option to change it --- src/lib/Bcfg2/Options.py | 6 ++++++ src/lib/Bcfg2/Server/BuiltinCore.py | 18 ++++++++---------- src/lib/Bcfg2/Server/CherryPyCore.py | 6 ++++-- src/lib/Bcfg2/Server/Core.py | 2 ++ 4 files changed, 20 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/lib/Bcfg2/Options.py b/src/lib/Bcfg2/Options.py index f3765a5ec..b418d57b0 100644 --- a/src/lib/Bcfg2/Options.py +++ b/src/lib/Bcfg2/Options.py @@ -577,6 +577,11 @@ SERVER_VCS_ROOT = \ default=None, odesc='', cf=('server', 'vcs_root')) +SERVER_UMASK = \ + Option('Server umask', + default='0077', + odesc='', + cf=('server', 'umask')) # database options DB_ENGINE = \ @@ -1068,6 +1073,7 @@ CLI_COMMON_OPTIONS = dict(configfile=CFILE, syslog=LOGGING_SYSLOG) DAEMON_COMMON_OPTIONS = dict(daemon=DAEMON, + umask=SERVER_UMASK, listen_all=SERVER_LISTEN_ALL, daemon_uid=SERVER_DAEMON_USER, daemon_gid=SERVER_DAEMON_GROUP) diff --git a/src/lib/Bcfg2/Server/BuiltinCore.py b/src/lib/Bcfg2/Server/BuiltinCore.py index 69fb8d0cb..63149c15e 100644 --- a/src/lib/Bcfg2/Server/BuiltinCore.py +++ b/src/lib/Bcfg2/Server/BuiltinCore.py @@ -28,17 +28,15 @@ class Core(BaseCore): #: this server core self.server = None + daemon_args = dict(uid=self.setup['daemon_uid'], + gid=self.setup['daemon_gid'], + umask=int(self.setup['umask'], 8)) if self.setup['daemon']: - #: The :class:`daemon.DaemonContext` used to drop - #: privileges, write the PID file (with :class:`PidFile`), - #: and daemonize this core. - self.context = \ - daemon.DaemonContext(uid=self.setup['daemon_uid'], - gid=self.setup['daemon_gid'], - pidfile=PIDLockFile(self.setup['daemon'])) - else: - self.context = daemon.DaemonContext(uid=self.setup['daemon_uid'], - gid=self.setup['daemon_gid']) + daemon_args['pidfile'] = PIDLockFile(self.setup['daemon']) + #: The :class:`daemon.DaemonContext` used to drop + #: privileges, write the PID file (with :class:`PidFile`), + #: and daemonize this core. + self.context = daemon.DaemonContext(**daemon_args) __init__.__doc__ = BaseCore.__init__.__doc__.split('.. -----')[0] def _dispatch(self, method, args, dispatch_dict): diff --git a/src/lib/Bcfg2/Server/CherryPyCore.py b/src/lib/Bcfg2/Server/CherryPyCore.py index 4ddcd7bdf..d097fd08f 100644 --- a/src/lib/Bcfg2/Server/CherryPyCore.py +++ b/src/lib/Bcfg2/Server/CherryPyCore.py @@ -107,8 +107,10 @@ class Core(BaseCore): :class:`cherrypy.process.plugins.DropPrivileges`, daemonize with :class:`cherrypy.process.plugins.Daemonizer`, and write a PID file with :class:`cherrypy.process.plugins.PIDFile`. """ - DropPrivileges(cherrypy.engine, uid=self.setup['daemon_uid'], - gid=self.setup['daemon_gid']).subscribe() + DropPrivileges(cherrypy.engine, + uid=self.setup['daemon_uid'], + gid=self.setup['daemon_gid'], + umask=int(self.setup['umask'], 8)).subscribe() Daemonizer(cherrypy.engine).subscribe() PIDFile(cherrypy.engine, self.setup['daemon']).subscribe() return True diff --git a/src/lib/Bcfg2/Server/Core.py b/src/lib/Bcfg2/Server/Core.py index cd2aa949f..6d0ad2bb9 100644 --- a/src/lib/Bcfg2/Server/Core.py +++ b/src/lib/Bcfg2/Server/Core.py @@ -665,6 +665,8 @@ class BaseCore(object): os.chmod(piddir, 420) # 0644 if not self._daemonize(): return False + else: + os.umask(int(self.setup['umask'], 8)) if not self._run(): self.shutdown() -- cgit v1.2.3-1-g7c22 From a985d238e6eee195878e42b8fa7b37f9cd27f9ac Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Wed, 14 Nov 2012 11:56:58 -0500 Subject: SSLCA: fixed variable names --- src/lib/Bcfg2/Server/Plugins/SSLCA.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/lib/Bcfg2/Server/Plugins/SSLCA.py b/src/lib/Bcfg2/Server/Plugins/SSLCA.py index a920a9cca..62396f860 100644 --- a/src/lib/Bcfg2/Server/Plugins/SSLCA.py +++ b/src/lib/Bcfg2/Server/Plugins/SSLCA.py @@ -278,7 +278,7 @@ class SSLCA(Bcfg2.Server.Plugin.GroupSpool): used to generate the required certificate request """ # create temp request config file - fh, fname = tempfile.mkstemp() + fd, fname = tempfile.mkstemp() cfp = ConfigParser.ConfigParser({}) cfp.optionxform = str defaults = { @@ -312,7 +312,7 @@ class SSLCA(Bcfg2.Server.Plugin.GroupSpool): cfp.set('req_distinguished_name', 'CN', metadata.hostname) self.debug_log("SSLCA: Writing temporary request config to %s" % fname) try: - cfp.write(os.fdopen(fh, 'w')) + cfp.write(os.fdopen(fd, 'w')) except IOError: raise PluginExecutionError("SSLCA: Failed to write temporary CSR " "config file: %s" % sys.exc_info()[1]) @@ -322,8 +322,8 @@ class SSLCA(Bcfg2.Server.Plugin.GroupSpool): """ creates the certificate request """ - fh, req = tempfile.mkstemp() - os.close(fh) + fd, req = tempfile.mkstemp() + os.close(fd) days = self.cert_specs[entry.get('name')]['days'] key = self.data + key_filename cmd = ["openssl", "req", "-new", "-config", req_config, -- cgit v1.2.3-1-g7c22 From 5d58c0435d8d3889d5fa889a65b61565da0a95f6 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Thu, 15 Nov 2012 10:09:47 -0500 Subject: Git: only support GitPython; only support Git.Update with GitPython dulwich is terrible. impressively so. git pull has a bug that prevents it from honoring --work-tree in many, many versions --- src/lib/Bcfg2/Server/Plugins/Git.py | 139 +++++++----------------------------- 1 file changed, 26 insertions(+), 113 deletions(-) (limited to 'src') diff --git a/src/lib/Bcfg2/Server/Plugins/Git.py b/src/lib/Bcfg2/Server/Plugins/Git.py index 5faa6c018..61d581009 100644 --- a/src/lib/Bcfg2/Server/Plugins/Git.py +++ b/src/lib/Bcfg2/Server/Plugins/Git.py @@ -1,119 +1,15 @@ """ The Git plugin provides a revision interface for Bcfg2 repos using git. """ -import os import sys import Bcfg2.Server.Plugin - - -class GitAPIBase(object): - """ Base class for the various Git APIs (dulwich, GitPython, - subprocesses) """ - def __init__(self, path): - self.path = path - - def revision(self): - """ Get the current revision of the git repo as a string """ - raise NotImplementedError - - def pull(self): - """ Pull the latest version of the upstream git repo and - rebase against it. """ - raise NotImplementedError - +from subprocess import Popen, PIPE try: - from dulwich.client import get_transport_and_path - from dulwich.repo import Repo - from dulwich.file import GitFile, ensure_dir_exists - - class GitAPI(GitAPIBase): - """ API for :class:`Git` using :mod:`dulwich` """ - def __init__(self, path): - GitAPIBase.__init__(self, path) - self.repo = Repo(self.path) - self.client, self.origin_path = get_transport_and_path( - self.repo.get_config().get(("remote", "origin"), - "url")) - - def revision(self): - return self.repo.head() - - def pull(self): - try: - remote_refs = self.client.fetch( - self.origin_path, self.repo, - determine_wants=self.repo.object_store.determine_wants_all) - except KeyError: - etype, err = sys.exc_info()[:2] - # try to work around bug - # https://bugs.launchpad.net/dulwich/+bug/1025886 - try: - # pylint: disable=W0212 - self.client._fetch_capabilities.remove('thin-pack') - # pylint: enable=W0212 - except KeyError: - raise etype(err) - remote_refs = self.client.fetch( - self.origin_path, self.repo, - determine_wants=self.repo.object_store.determine_wants_all) - - tree_id = self.repo[remote_refs['HEAD']].tree - # iterate over tree content, giving path and blob sha. - for entry in self.repo.object_store.iter_tree_contents(tree_id): - entry_in_path = entry.in_path(self.repo.path) - ensure_dir_exists(os.path.split(entry_in_path.path)[0]) - GitFile(entry_in_path.path, - 'wb').write(self.repo[entry.sha].data) - + import git + HAS_GITPYTHON = True except ImportError: - try: - import git - - class GitAPI(GitAPIBase): - """ API for :class:`Git` using :mod:`git` (GitPython) """ - def __init__(self, path): - GitAPIBase.__init__(self, path) - self.repo = git.Repo(path) - - def revision(self): - return self.repo.head.commit.hexsha - - def pull(self): - self.repo.git.pull("--rebase") - - except ImportError: - from subprocess import Popen, PIPE - - try: - Popen(["git"], stdout=PIPE, stderr=PIPE).wait() - - class GitAPI(GitAPIBase): - """ API for :class:`Git` using subprocess to run git - commands """ - def revision(self): - proc = Popen(["git", "--work-tree", - os.path.join(self.path, ".git"), - "rev-parse", "HEAD"], stdout=PIPE, - stderr=PIPE) - rv, err = proc.communicate() - if proc.wait(): - raise Exception("Git: Error getting revision from %s: " - "%s" % (self.path, err)) - return rv.strip() # pylint: disable=E1103 - - def pull(self): - proc = Popen(["git", "--work-tree", - os.path.join(self.path, ".git"), - "pull", "--rebase"], stdout=PIPE, - stderr=PIPE) - err = proc.communicate()[1].strip() - if proc.wait(): - raise Exception("Git: Error pulling: %s" % err) - - except OSError: - raise ImportError("Could not import dulwich or GitPython " - "libraries, and no 'git' command found in PATH") + HAS_GITPYTHON = False class Git(Bcfg2.Server.Plugin.Version): @@ -121,21 +17,38 @@ class Git(Bcfg2.Server.Plugin.Version): using git. """ __author__ = 'bcfg-dev@mcs.anl.gov' __vcs_metadata_path__ = ".git" - __rmi__ = Bcfg2.Server.Plugin.Version.__rmi__ + ['Update'] + if HAS_GITPYTHON: + __rmi__ = Bcfg2.Server.Plugin.Version.__rmi__ + ['Update'] def __init__(self, core, datastore): Bcfg2.Server.Plugin.Version.__init__(self, core, datastore) - self.repo = GitAPI(self.vcs_root) + if HAS_GITPYTHON: + self.repo = git.Repo(self.vcs_root) + else: + self.logger.debug("Git: GitPython not found, using CLI interface " + "to Git") + self.repo = None self.logger.debug("Initialized git plugin with git directory %s" % self.vcs_path) def get_revision(self): """Read git revision information for the Bcfg2 repository.""" try: - return self.repo.revision() + if HAS_GITPYTHON: + return self.repo.head.commit.hexsha + else: + cmd = ["git", "--git-dir", self.vcs_path, + "--work-tree", self.vcs_root, "rev-parse", "HEAD"] + self.debug_log("Git: Running cmd") + proc = Popen(cmd, stdout=PIPE, stderr=PIPE) + rv, err = proc.communicate() + if proc.wait(): + raise Exception(err) + return rv except: err = sys.exc_info()[1] - msg = "Failed to read git repository: %s" % err + msg = "Git: Error getting revision from %s: %s" % (self.vcs_root, + err) self.logger.error(msg) raise Bcfg2.Server.Plugin.PluginExecutionError(msg) @@ -144,7 +57,7 @@ class Git(Bcfg2.Server.Plugin.Version): Update the working copy against the upstream repository """ try: - self.repo.pull() + self.repo.git.pull("--rebase") self.logger.info("Git repo at %s updated to %s" % (self.vcs_root, self.get_revision())) return True -- cgit v1.2.3-1-g7c22 From a6a29aa01744cc893741ddf558f415b7c705d3f6 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Thu, 15 Nov 2012 15:25:21 -0500 Subject: POSIX: fixed removal of symlinked directories --- src/lib/Bcfg2/Client/Tools/POSIX/Directory.py | 16 ++-------------- src/lib/Bcfg2/Client/Tools/POSIX/Nonexistent.py | 23 +++++++++++------------ src/lib/Bcfg2/Client/Tools/POSIX/base.py | 18 +++++++++++++----- 3 files changed, 26 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/src/lib/Bcfg2/Client/Tools/POSIX/Directory.py b/src/lib/Bcfg2/Client/Tools/POSIX/Directory.py index 9b0b998bb..9d0fe05e0 100644 --- a/src/lib/Bcfg2/Client/Tools/POSIX/Directory.py +++ b/src/lib/Bcfg2/Client/Tools/POSIX/Directory.py @@ -3,7 +3,6 @@ import os import sys import stat -import shutil import Bcfg2.Client.XML from Bcfg2.Client.Tools.POSIX.base import POSIXTool @@ -67,25 +66,14 @@ class POSIXDirectory(POSIXTool): rv &= self._makedirs(entry) if entry.get('prune', 'false') == 'true': - ulfailed = False for pent in entry.findall('Prune'): pname = pent.get('path') - ulfailed = False - if os.path.isdir(pname): - remove = shutil.rmtree - else: - remove = os.unlink try: self.logger.debug("POSIX: Removing %s" % pname) - remove(pname) + self._remove(pent) except OSError: err = sys.exc_info()[1] self.logger.error("POSIX: Failed to unlink %s: %s" % (pname, err)) - ulfailed = True - if ulfailed: - # even if prune failed, we still want to install the - # entry to make sure that we get permissions and - # whatnot set - rv = False + rv = False return POSIXTool.install(self, entry) and rv diff --git a/src/lib/Bcfg2/Client/Tools/POSIX/Nonexistent.py b/src/lib/Bcfg2/Client/Tools/POSIX/Nonexistent.py index 5f1fbbe7c..0606d47f9 100644 --- a/src/lib/Bcfg2/Client/Tools/POSIX/Nonexistent.py +++ b/src/lib/Bcfg2/Client/Tools/POSIX/Nonexistent.py @@ -2,7 +2,6 @@ import os import sys -import shutil from Bcfg2.Client.Tools.POSIX.base import POSIXTool @@ -19,25 +18,25 @@ class POSIXNonexistent(POSIXTool): def install(self, entry): ename = entry.get('name') - if entry.get('recursive', '').lower() == 'true': + recursive = entry.get('recursive', '').lower() == 'true' + if recursive: + print "here" # ensure that configuration spec is consistent first for struct in self.config.getchildren(): - for entry in struct.getchildren(): - if (entry.tag == 'Path' and - entry.get('type') != 'nonexistent' and - entry.get('name').startswith(ename)): + print "checking struct" + for el in struct.getchildren(): + import lxml.etree + print "checking entry: %s" % lxml.etree.tostring(el) + if (el.tag == 'Path' and + el.get('type') != 'nonexistent' and + el.get('name').startswith(ename)): self.logger.error('POSIX: Not removing %s. One or ' 'more files in this directory are ' 'specified in your configuration.' % ename) return False - remove = shutil.rmtree - elif os.path.isdir(ename): - remove = os.rmdir - else: - remove = os.remove try: - remove(ename) + self._remove(entry, recursive=recursive) return True except OSError: err = sys.exc_info()[1] diff --git a/src/lib/Bcfg2/Client/Tools/POSIX/base.py b/src/lib/Bcfg2/Client/Tools/POSIX/base.py index a9566b698..6388f6731 100644 --- a/src/lib/Bcfg2/Client/Tools/POSIX/base.py +++ b/src/lib/Bcfg2/Client/Tools/POSIX/base.py @@ -66,18 +66,26 @@ class POSIXTool(Bcfg2.Client.Tools.Tool): rv &= self._set_perms(entry, path=os.path.join(root, path)) return rv + def _remove(self, entry, recursive=True): + """ Remove a Path entry, whatever that takes """ + if os.path.islink(entry.get('name')): + os.unlink(entry.get('name')) + elif os.path.isdir(entry.get('name')): + if recursive: + shutil.rmtree(entry.get('name')) + else: + os.rmdir(entry.get('name')) + else: + os.unlink(entry.get('name')) + def _exists(self, entry, remove=False): """ check for existing paths and optionally remove them. if the path exists, return the lstat of it """ try: ondisk = os.lstat(entry.get('name')) if remove: - if os.path.isdir(entry.get('name')): - remove = shutil.rmtree - else: - remove = os.unlink try: - remove(entry.get('name')) + self._remove(entry) return None except OSError: err = sys.exc_info()[1] -- cgit v1.2.3-1-g7c22 From 12684bada59c9ddc08165dad757682514b54634c Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Thu, 15 Nov 2012 17:03:23 -0500 Subject: Git: Added ability to update to a specific tree-ish --- src/lib/Bcfg2/Server/Plugins/Git.py | 51 +++++++++++++++++++++++++++++-------- 1 file changed, 41 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/lib/Bcfg2/Server/Plugins/Git.py b/src/lib/Bcfg2/Server/Plugins/Git.py index 61d581009..8cc63a46f 100644 --- a/src/lib/Bcfg2/Server/Plugins/Git.py +++ b/src/lib/Bcfg2/Server/Plugins/Git.py @@ -52,17 +52,48 @@ class Git(Bcfg2.Server.Plugin.Version): self.logger.error(msg) raise Bcfg2.Server.Plugin.PluginExecutionError(msg) - def Update(self): + def Update(self, ref=None): """ Git.Update() => True|False Update the working copy against the upstream repository """ + self.logger.info("Git: Git.Update(ref='%s')" % ref) + self.debug_log("Git: Performing garbage collection on repo at %s" % + self.vcs_root) try: - self.repo.git.pull("--rebase") - self.logger.info("Git repo at %s updated to %s" % - (self.vcs_root, self.get_revision())) - return True - except: # pylint: disable=W0702 - err = sys.exc_info()[1] - msg = "Failed to pull from git repository: %s" % err - self.logger.error(msg) - raise Bcfg2.Server.Plugin.PluginExecutionError(msg) + self.repo.git.gc('--auto') + except git.GitCommandError: + self.logger.warning("Git: Failed to perform garbage collection: %s" + % sys.exc_info()[1]) + + if ref: + self.debug_log("Git: Checking out %s" % ref) + try: + self.repo.git.checkout('-f', ref) + except git.GitCommandError: + err = sys.exc_info()[1] + msg = "Git: Failed to checkout %s: %s" % (ref, err) + self.logger.error(msg) + raise Bcfg2.Server.Plugin.PluginExecutionError(msg) + + # determine if we should try to pull to get the latest commit + # on this head + tracking = None + if not self.repo.head.is_detached: + self.debug_log("Git: Determining if %s is a tracking branch" % + self.repo.head.ref.name) + tracking = self.repo.head.ref.tracking_branch() + + if tracking is not None: + self.debug_log("Git: %s is a tracking branch, pulling from %s" % + (self.repo.head.ref.name, tracking)) + try: + self.repo.git.pull("--rebase") + except: # pylint: disable=W0702 + err = sys.exc_info()[1] + msg = "Git: Failed to pull from upstream: %s" % err + self.logger.error(msg) + raise Bcfg2.Server.Plugin.PluginExecutionError(msg) + + self.logger.info("Git: Repo at %s updated to %s" % + (self.vcs_root, self.get_revision())) + return True -- cgit v1.2.3-1-g7c22 From 00627ba56075a0d0cb42356624ae6989521270bc Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Fri, 16 Nov 2012 08:04:59 -0500 Subject: cleaned up Templatehelper to help avoid some event handling errors --- src/lib/Bcfg2/Server/Plugins/TemplateHelper.py | 46 +++++++++++++++----------- 1 file changed, 26 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/lib/Bcfg2/Server/Plugins/TemplateHelper.py b/src/lib/Bcfg2/Server/Plugins/TemplateHelper.py index 627c82f25..f09d4839e 100644 --- a/src/lib/Bcfg2/Server/Plugins/TemplateHelper.py +++ b/src/lib/Bcfg2/Server/Plugins/TemplateHelper.py @@ -13,15 +13,25 @@ LOGGER = logging.getLogger(__name__) MODULE_RE = re.compile(r'(?P(?P[^\/]+)\.py)$') -class HelperModule(Bcfg2.Server.Plugin.FileBacked): +class HelperModule(object): """ Representation of a TemplateHelper module """ def __init__(self, name, fam=None): - Bcfg2.Server.Plugin.FileBacked.__init__(self, name, fam=fam) + self.name = name + self.fam = fam self._module_name = MODULE_RE.search(self.name).group('module') self._attrs = [] - def Index(self): + def HandleEvent(self, event=None): + """ HandleEvent is called whenever the FAM registers an event. + + :param event: The event object + :type event: Bcfg2.Server.FileMonitor.Event + :returns: None + """ + if event and event.code2str() not in ['exists', 'changed', 'created']: + return + try: module = imp.load_source(self._module_name, self.name) except: # pylint: disable=W0702 @@ -54,27 +64,23 @@ class HelperModule(Bcfg2.Server.Plugin.FileBacked): self._attrs = newattrs -class HelperSet(Bcfg2.Server.Plugin.DirectoryBacked): - """ A set of template helper modules """ - ignore = re.compile("^(\.#.*|.*~|\\..*\\.(sw[px])|.*\.py[co])$") - patterns = MODULE_RE - __child__ = HelperModule - - class TemplateHelper(Bcfg2.Server.Plugin.Plugin, - Bcfg2.Server.Plugin.Connector): + Bcfg2.Server.Plugin.Connector, + Bcfg2.Server.Plugin.DirectoryBacked): """ A plugin to provide helper classes and functions to templates """ - name = 'TemplateHelper' __author__ = 'chris.a.st.pierre@gmail.com' + ignore = re.compile("^(\.#.*|.*~|\\..*\\.(sw[px])|.*\.py[co])$") + patterns = MODULE_RE + __child__ = HelperModule def __init__(self, core, datastore): Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore) Bcfg2.Server.Plugin.Connector.__init__(self) - self.helpers = HelperSet(self.data, core.fam) + Bcfg2.Server.Plugin.DirectoryBacked.__init__(self, self.data, core.fam) def get_additional_data(self, _): return dict([(h._module_name, h) # pylint: disable=W0212 - for h in self.helpers.entries.values()]) + for h in self.entries.values()]) class TemplateHelperLint(Bcfg2.Server.Lint.ServerlessPlugin): @@ -130,9 +136,9 @@ class TemplateHelperLint(Bcfg2.Server.Lint.ServerlessPlugin): @classmethod def Errors(cls): - return {"templatehelper-import-error":"error", - "templatehelper-no-export":"error", - "templatehelper-nonlist-export":"error", - "templatehelper-nonexistent-export":"error", - "templatehelper-reserved-export":"error", - "templatehelper-underscore-export":"warning"} + return {"templatehelper-import-error": "error", + "templatehelper-no-export": "error", + "templatehelper-nonlist-export": "error", + "templatehelper-nonexistent-export": "error", + "templatehelper-reserved-export": "error", + "templatehelper-underscore-export": "warning"} -- cgit v1.2.3-1-g7c22 From 924ce4f763bbc0aa47a9f79c5279c61fa8070716 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Fri, 16 Nov 2012 09:22:06 -0500 Subject: FAM: allow toggling FAM debug by RMI on running server --- src/lib/Bcfg2/Server/Core.py | 4 ++++ src/lib/Bcfg2/Server/FileMonitor/Inotify.py | 4 ++-- src/lib/Bcfg2/Server/FileMonitor/__init__.py | 14 ++++---------- 3 files changed, 10 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/lib/Bcfg2/Server/Core.py b/src/lib/Bcfg2/Server/Core.py index 6d0ad2bb9..b48c19467 100644 --- a/src/lib/Bcfg2/Server/Core.py +++ b/src/lib/Bcfg2/Server/Core.py @@ -1069,3 +1069,7 @@ class BaseCore(object): """ Get current statistics about component execution from :attr:`Bcfg2.Statistics.stats`. """ return Bcfg2.Statistics.stats.display() + + @exposed + def toggle_fam_debug(self, _): + return self.fam.toggle_debug() diff --git a/src/lib/Bcfg2/Server/FileMonitor/Inotify.py b/src/lib/Bcfg2/Server/FileMonitor/Inotify.py index d5aa8e4ad..8a311c8c6 100644 --- a/src/lib/Bcfg2/Server/FileMonitor/Inotify.py +++ b/src/lib/Bcfg2/Server/FileMonitor/Inotify.py @@ -113,8 +113,8 @@ class Inotify(Pseudo, pyinotify.ProcessEvent): try: watch = self.watchmgr.watches[ievent.wd] except KeyError: - LOGGER.error("Error handling event for %s: Watch %s not found" % - (ievent.pathname, ievent.wd)) + LOGGER.error("Error handling event %s for %s: Watch %s not found" % + (action, ievent.pathname, ievent.wd)) return # FAM-style file monitors return the full path to the parent # directory that is being watched, relative paths to anything diff --git a/src/lib/Bcfg2/Server/FileMonitor/__init__.py b/src/lib/Bcfg2/Server/FileMonitor/__init__.py index 72b1d2dd7..dad0db44e 100644 --- a/src/lib/Bcfg2/Server/FileMonitor/__init__.py +++ b/src/lib/Bcfg2/Server/FileMonitor/__init__.py @@ -50,6 +50,7 @@ import sys import fnmatch import logging from time import sleep, time +from Bcfg2.Server.Plugin import Debuggable LOGGER = logging.getLogger(__name__) @@ -104,7 +105,7 @@ class Event(object): return "%s (request ID %s)" % (str(self), self.requestID) -class FileMonitor(object): +class FileMonitor(Debuggable): """ The base class that all FAM implementions must inherit. The simplest instance of a FileMonitor subclass needs only to add @@ -128,8 +129,8 @@ class FileMonitor(object): .. ----- .. autoattribute:: __priority__ """ - #: Whether or not to produce debug logging - self.debug = debug + Debuggable.__init__(self, name="FileMonitor") + self.debug_flag = debug #: A dict that records which objects handle which events. #: Keys are monitor handle IDs and values are objects whose @@ -168,13 +169,6 @@ class FileMonitor(object): example of this. """ self.started = True - def debug_log(self, msg): - """ Log a debug message. - - :param msg: The message to log iff :attr:`debug` is set.""" - if self.debug: - LOGGER.info(msg) - def should_ignore(self, event): """ Returns True if an event should be ignored, False otherwise. For events that include the full path, both the -- cgit v1.2.3-1-g7c22 From f30b6d7ef7d3ab5da95b0b7f945b479887aba653 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Fri, 16 Nov 2012 09:22:31 -0500 Subject: Core: added toggle_debug RMI to toggle all debug modes on running server --- src/lib/Bcfg2/Server/Core.py | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src') diff --git a/src/lib/Bcfg2/Server/Core.py b/src/lib/Bcfg2/Server/Core.py index b48c19467..7d980e58a 100644 --- a/src/lib/Bcfg2/Server/Core.py +++ b/src/lib/Bcfg2/Server/Core.py @@ -1070,6 +1070,12 @@ class BaseCore(object): :attr:`Bcfg2.Statistics.stats`. """ return Bcfg2.Statistics.stats.display() + @exposed + def toggle_debug(self, address): + for plugin in self.plugins.values(): + plugin.toggle_debug() + return self.toggle_fam_debug(address) + @exposed def toggle_fam_debug(self, _): return self.fam.toggle_debug() -- cgit v1.2.3-1-g7c22 From c57bcc40f4edad2666dc7b5fe718b2399d0edbf8 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Fri, 16 Nov 2012 09:28:18 -0500 Subject: Inotify: explicitly ignore events not in event mask --- src/lib/Bcfg2/Server/FileMonitor/Inotify.py | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src') diff --git a/src/lib/Bcfg2/Server/FileMonitor/Inotify.py b/src/lib/Bcfg2/Server/FileMonitor/Inotify.py index 8a311c8c6..178a47b1a 100644 --- a/src/lib/Bcfg2/Server/FileMonitor/Inotify.py +++ b/src/lib/Bcfg2/Server/FileMonitor/Inotify.py @@ -110,6 +110,13 @@ class Inotify(Pseudo, pyinotify.ProcessEvent): if ievent.mask & amask: action = aname break + else: + # event action is not in the mask, and thus is not + # something we care about + self.debug_log("Ignoring event %s for %s" % (action, + ievent.pathname)) + return + try: watch = self.watchmgr.watches[ievent.wd] except KeyError: -- cgit v1.2.3-1-g7c22 From 1d953e4512c8d4cc9ce536da3522a59d812d58b9 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Fri, 16 Nov 2012 09:28:37 -0500 Subject: added set_debug RMI for plugins and core, set_fam_debug RMI --- src/lib/Bcfg2/Server/Core.py | 10 ++++++++++ src/lib/Bcfg2/Server/FileMonitor/__init__.py | 2 +- src/lib/Bcfg2/Server/Plugin/base.py | 18 +++++++++++++----- 3 files changed, 24 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/lib/Bcfg2/Server/Core.py b/src/lib/Bcfg2/Server/Core.py index 7d980e58a..c23d3cf24 100644 --- a/src/lib/Bcfg2/Server/Core.py +++ b/src/lib/Bcfg2/Server/Core.py @@ -1079,3 +1079,13 @@ class BaseCore(object): @exposed def toggle_fam_debug(self, _): return self.fam.toggle_debug() + + @exposed + def set_debug(self, address, debug): + for plugin in self.plugins.values(): + plugin.set_debug(debug) + return self.set_fam_debug(address, debug) + + @exposed + def set_fam_debug(self, _, debug): + return self.fam.set_debug(debug) diff --git a/src/lib/Bcfg2/Server/FileMonitor/__init__.py b/src/lib/Bcfg2/Server/FileMonitor/__init__.py index dad0db44e..42ad4c041 100644 --- a/src/lib/Bcfg2/Server/FileMonitor/__init__.py +++ b/src/lib/Bcfg2/Server/FileMonitor/__init__.py @@ -129,7 +129,7 @@ class FileMonitor(Debuggable): .. ----- .. autoattribute:: __priority__ """ - Debuggable.__init__(self, name="FileMonitor") + Debuggable.__init__(self) self.debug_flag = debug #: A dict that records which objects handle which events. diff --git a/src/lib/Bcfg2/Server/Plugin/base.py b/src/lib/Bcfg2/Server/Plugin/base.py index 8d288f835..e74909ee9 100644 --- a/src/lib/Bcfg2/Server/Plugin/base.py +++ b/src/lib/Bcfg2/Server/Plugin/base.py @@ -9,7 +9,7 @@ class Debuggable(object): via XML-RPC on :class:`Bcfg2.Server.Plugin.base.Plugin` objects """ #: List of names of methods to be exposed as XML-RPC functions - __rmi__ = ['toggle_debug'] + __rmi__ = ['toggle_debug', 'set_debug'] def __init__(self, name=None): """ @@ -26,17 +26,25 @@ class Debuggable(object): self.debug_flag = False self.logger = logging.getLogger(name) - def toggle_debug(self): - """ Turn debugging output on or off. This method is exposed + def set_debug(self, debug): + """ Explicitly enable or disable debugging. This method is exposed via XML-RPC. :returns: bool - The new value of the debug flag """ - self.debug_flag = not self.debug_flag + self.debug_flag = debug self.debug_log("%s: debug_flag = %s" % (self.__class__.__name__, self.debug_flag), flag=True) - return self.debug_flag + return debug + + def toggle_debug(self): + """ Turn debugging output on or off. This method is exposed + via XML-RPC. + + :returns: bool - The new value of the debug flag + """ + return self.set_debug(not self.debug_flag) def debug_log(self, message, flag=None): """ Log a message at the debug level. -- cgit v1.2.3-1-g7c22 From 0ac9997e9781f6b5beb47107431d960077234139 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Fri, 16 Nov 2012 09:46:36 -0500 Subject: documented new core debug RMIs --- src/lib/Bcfg2/Server/Core.py | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/lib/Bcfg2/Server/Core.py b/src/lib/Bcfg2/Server/Core.py index c23d3cf24..ee875a7e8 100644 --- a/src/lib/Bcfg2/Server/Core.py +++ b/src/lib/Bcfg2/Server/Core.py @@ -1067,25 +1067,59 @@ class BaseCore(object): @exposed def get_statistics(self, _): """ Get current statistics about component execution from - :attr:`Bcfg2.Statistics.stats`. """ + :attr:`Bcfg2.Statistics.stats`. + + :returns: dict - The statistics data as returned by + :func:`Bcfg2.Statistics.Statistics.display` """ return Bcfg2.Statistics.stats.display() @exposed def toggle_debug(self, address): + """ Toggle debug status of the FAM and all plugins + + :param address: Client (address, hostname) pair + :type address: tuple + :returns: bool - The new debug state of the FAM + """ for plugin in self.plugins.values(): plugin.toggle_debug() return self.toggle_fam_debug(address) @exposed def toggle_fam_debug(self, _): + """ Toggle debug status of the FAM + + :returns: bool - The new debug state of the FAM + """ return self.fam.toggle_debug() @exposed def set_debug(self, address, debug): + """ Explicitly set debug status of the FAM and all plugins + + :param debug: The new debug status. This can either be a + boolean, or a string describing the state (e.g., + "true" or "false"; case-insensitive) + :type debug: bool or string + :returns: bool - The new debug state + """ + if debug not in [True, False]: + debug = debug.lower() == "true" for plugin in self.plugins.values(): plugin.set_debug(debug) return self.set_fam_debug(address, debug) @exposed def set_fam_debug(self, _, debug): + """ Explicitly set debug status of the FAM + + :param debug: The new debug status of the FAM. This can + either be a boolean, or a string describing the + state (e.g., "true" or "false"; + case-insensitive) + :type debug: bool or string + :returns: bool - The new debug state of the FAM + """ + if debug not in [True, False]: + debug = debug.lower() == "true" return self.fam.set_debug(debug) -- cgit v1.2.3-1-g7c22 From 71dcf9695831e48f2c41f5d5b8ac3022c352ee46 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Fri, 16 Nov 2012 09:47:01 -0500 Subject: fixed plugin-specific implementations of toggle_debug for new set_debug stuff --- src/lib/Bcfg2/Server/Plugin/helpers.py | 10 +++++----- src/lib/Bcfg2/Server/Plugins/Packages/PackagesSources.py | 8 ++++---- src/lib/Bcfg2/Server/Plugins/Packages/__init__.py | 10 +++++----- 3 files changed, 14 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/lib/Bcfg2/Server/Plugin/helpers.py b/src/lib/Bcfg2/Server/Plugin/helpers.py index 894ed9851..318bf03f1 100644 --- a/src/lib/Bcfg2/Server/Plugin/helpers.py +++ b/src/lib/Bcfg2/Server/Plugin/helpers.py @@ -1526,12 +1526,12 @@ class GroupSpool(Plugin, Generator): else: return self.handles[event.requestID].rstrip("/") - def toggle_debug(self): + def set_debug(self, debug): for entry in self.entries.values(): - if hasattr(entry, "toggle_debug"): - entry.toggle_debug() - return Plugin.toggle_debug(self) - toggle_debug.__doc__ = Plugin.toggle_debug.__doc__ + if hasattr(entry, "set_debug"): + entry.set_debug(debug) + return Plugin.set_debug(self, debug) + set_debug.__doc__ = Plugin.set_debug.__doc__ def HandleEvent(self, event): """ HandleEvent is the event dispatcher for GroupSpool diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/PackagesSources.py b/src/lib/Bcfg2/Server/Plugins/Packages/PackagesSources.py index 2c3ac2096..2735e389a 100644 --- a/src/lib/Bcfg2/Server/Plugins/Packages/PackagesSources.py +++ b/src/lib/Bcfg2/Server/Plugins/Packages/PackagesSources.py @@ -75,11 +75,11 @@ class PackagesSources(Bcfg2.Server.Plugin.StructFile, #: should be told to reload its data. self.parsed = set() - def toggle_debug(self): - Bcfg2.Server.Plugin.Debuggable.toggle_debug(self) + def set_debug(self, debug): + Bcfg2.Server.Plugin.Debuggable.set_debug(self, debug) for source in self.entries: - source.toggle_debug() - toggle_debug.__doc__ = Bcfg2.Server.Plugin.Plugin.toggle_debug.__doc__ + source.set_debug(debug) + set_debug.__doc__ = Bcfg2.Server.Plugin.Plugin.set_debug.__doc__ def HandleEvent(self, event=None): """ HandleEvent is called whenever the FAM registers an event. diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/__init__.py b/src/lib/Bcfg2/Server/Plugins/Packages/__init__.py index 5a193219c..f30e060bd 100644 --- a/src/lib/Bcfg2/Server/Plugins/Packages/__init__.py +++ b/src/lib/Bcfg2/Server/Plugins/Packages/__init__.py @@ -113,13 +113,13 @@ class Packages(Bcfg2.Server.Plugin.Plugin, __init__.__doc__ = Bcfg2.Server.Plugin.Plugin.__init__.__doc__ - def toggle_debug(self): - rv = Bcfg2.Server.Plugin.Plugin.toggle_debug(self) - self.sources.toggle_debug() + def set_debug(self, debug): + rv = Bcfg2.Server.Plugin.Plugin.set_debug(self, debug) + self.sources.set_debug(debug) for collection in self.collections.values(): - collection.toggle_debug() + collection.set_debug(debug) return rv - toggle_debug.__doc__ = Bcfg2.Server.Plugin.Plugin.toggle_debug.__doc__ + set_debug.__doc__ = Bcfg2.Server.Plugin.Plugin.set_debug.__doc__ @property def disableResolver(self): -- cgit v1.2.3-1-g7c22 From 2e1282d2da6986acd61d7eaf69676a303c6050f3 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Fri, 16 Nov 2012 10:50:49 -0500 Subject: removed bogus print statements --- src/lib/Bcfg2/Client/Tools/POSIX/Nonexistent.py | 3 --- src/lib/Bcfg2/Server/Admin/Reports.py | 2 +- src/sbin/bcfg2-info | 7 +++---- 3 files changed, 4 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/lib/Bcfg2/Client/Tools/POSIX/Nonexistent.py b/src/lib/Bcfg2/Client/Tools/POSIX/Nonexistent.py index 0606d47f9..7320f8f16 100644 --- a/src/lib/Bcfg2/Client/Tools/POSIX/Nonexistent.py +++ b/src/lib/Bcfg2/Client/Tools/POSIX/Nonexistent.py @@ -20,13 +20,10 @@ class POSIXNonexistent(POSIXTool): ename = entry.get('name') recursive = entry.get('recursive', '').lower() == 'true' if recursive: - print "here" # ensure that configuration spec is consistent first for struct in self.config.getchildren(): - print "checking struct" for el in struct.getchildren(): import lxml.etree - print "checking entry: %s" % lxml.etree.tostring(el) if (el.tag == 'Path' and el.get('type') != 'nonexistent' and el.get('name').startswith(ename)): diff --git a/src/lib/Bcfg2/Server/Admin/Reports.py b/src/lib/Bcfg2/Server/Admin/Reports.py index 15ff79a35..6e313e84b 100644 --- a/src/lib/Bcfg2/Server/Admin/Reports.py +++ b/src/lib/Bcfg2/Server/Admin/Reports.py @@ -74,7 +74,7 @@ class Reports(Bcfg2.Server.Admin.Mode): try: import south except ImportError: - print "Django south is required for Reporting" + print("Django south is required for Reporting") raise SystemExit(-3) def __call__(self, args): diff --git a/src/sbin/bcfg2-info b/src/sbin/bcfg2-info index 7277fa765..acb9e4f44 100755 --- a/src/sbin/bcfg2-info +++ b/src/sbin/bcfg2-info @@ -94,7 +94,7 @@ def load_interpreters(): best = "bpython" except ImportError: pass - + try: # whether ipython is actually better than bpython is # up for debate, but this is the behavior that existed @@ -454,7 +454,7 @@ Bcfg2 client itself.""") 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')] @@ -503,7 +503,6 @@ Bcfg2 client itself.""") pretty = True alist.remove('-p') if len(alist) != 1: - print 'alist=%s' % alist print(self._get_usage(self.do_probes)) return hostname = alist[0] @@ -736,7 +735,7 @@ Bcfg2 client itself.""") def _block(self): pass - + def build_usage(): -- cgit v1.2.3-1-g7c22 From 5afd0515a04dc0f5cced275f56d108057a842f97 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Fri, 16 Nov 2012 11:47:24 -0500 Subject: removed bogus lxml import --- src/lib/Bcfg2/Client/Tools/POSIX/Nonexistent.py | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/lib/Bcfg2/Client/Tools/POSIX/Nonexistent.py b/src/lib/Bcfg2/Client/Tools/POSIX/Nonexistent.py index 7320f8f16..f7251ca50 100644 --- a/src/lib/Bcfg2/Client/Tools/POSIX/Nonexistent.py +++ b/src/lib/Bcfg2/Client/Tools/POSIX/Nonexistent.py @@ -23,7 +23,6 @@ class POSIXNonexistent(POSIXTool): # ensure that configuration spec is consistent first for struct in self.config.getchildren(): for el in struct.getchildren(): - import lxml.etree if (el.tag == 'Path' and el.get('type') != 'nonexistent' and el.get('name').startswith(ename)): -- cgit v1.2.3-1-g7c22