summaryrefslogtreecommitdiffstats
path: root/src/sbin
diff options
context:
space:
mode:
authorChris St. Pierre <chris.a.st.pierre@gmail.com>2012-10-17 11:21:27 -0400
committerChris St. Pierre <chris.a.st.pierre@gmail.com>2012-10-17 11:21:41 -0400
commit7c3368f78e7c5042932a4fb58cea4b2ac3130358 (patch)
tree39ea7d392fe118b91df702cce6bf0a0e3963c11e /src/sbin
parent6683f2e8d48b1cbf8e4c1ad096c6b0c98eefe527 (diff)
downloadbcfg2-7c3368f78e7c5042932a4fb58cea4b2ac3130358.tar.gz
bcfg2-7c3368f78e7c5042932a4fb58cea4b2ac3130358.tar.bz2
bcfg2-7c3368f78e7c5042932a4fb58cea4b2ac3130358.zip
added bcfg2_local.py, a tool to run bcfg2 against a local specification
Diffstat (limited to 'src/sbin')
-rwxr-xr-xsrc/sbin/bcfg2344
-rwxr-xr-xsrc/sbin/bcfg2-info2
2 files changed, 13 insertions, 333 deletions
diff --git a/src/sbin/bcfg2 b/src/sbin/bcfg2
index f7c36cff2..91d09b959 100755
--- a/src/sbin/bcfg2
+++ b/src/sbin/bcfg2
@@ -1,25 +1,10 @@
#!/usr/bin/env python
-
"""Bcfg2 Client"""
-import fcntl
-import logging
-import os
-import signal
-import socket
-import stat
import sys
-import tempfile
-import time
-import Bcfg2.Proxy
-import Bcfg2.Logger
+import signal
import Bcfg2.Options
-import Bcfg2.Client.XML
-import Bcfg2.Client.Frame
-import Bcfg2.Client.Tools
-from Bcfg2.Compat import xmlrpclib
-from Bcfg2.version import __version__
-from subprocess import Popen, PIPE
+from Bcfg2.Client import Client
def cb_sigint_handler(signum, frame):
@@ -27,323 +12,18 @@ def cb_sigint_handler(signum, frame):
raise SystemExit(1)
-class Client(object):
- """The main bcfg2 client class"""
-
- def __init__(self):
- self.toolset = None
- self.tools = None
- self.config = None
- self._proxy = None
-
- optinfo = Bcfg2.Options.CLIENT_COMMON_OPTIONS
- self.setup = Bcfg2.Options.OptionParser(optinfo)
- self.setup.parse(sys.argv[1:])
-
- if self.setup['args']:
- print("Bcfg2 takes no arguments, only options")
- print(self.setup.buildHelpMessage())
- raise SystemExit(1)
- if self.setup['debug']:
- level = logging.DEBUG
- elif self.setup['verbose']:
- level = logging.INFO
- else:
- level = logging.WARNING
- Bcfg2.Logger.setup_logging('bcfg2',
- to_syslog=self.setup['syslog'],
- level=level,
- to_file=self.setup['logging'])
- self.logger = logging.getLogger('bcfg2')
- self.logger.debug(self.setup)
- if self.setup['bundle_quick']:
- if not self.setup['bundle'] and not self.setup['skipbundle']:
- self.logger.error("-Q option requires -b or -B")
- raise SystemExit(1)
- elif self.setup['remove']:
- self.logger.error("-Q option incompatible with -r")
- raise SystemExit(1)
- if 'drivers' in self.setup and self.setup['drivers'] == 'help':
- self.logger.info("The following drivers are available:")
- self.logger.info(Bcfg2.Client.Tools.drivers)
- raise SystemExit(0)
- if self.setup['remove'] and 'services' in self.setup['remove'].lower():
- self.logger.error("Service removal is nonsensical; "
- "removed services will only be disabled")
- if (self.setup['remove'] and
- self.setup['remove'].lower() not in ['all', 'services',
- 'packages']):
- self.logger.error("Got unknown argument %s for -r" %
- self.setup['remove'])
- if self.setup["file"] and self.setup["cache"]:
- print("cannot use -f and -c together")
- raise SystemExit(1)
- if not self.setup['server'].startswith('https://'):
- self.setup['server'] = 'https://' + self.setup['server']
+def main():
+ optinfo = Bcfg2.Options.CLIENT_COMMON_OPTIONS
+ setup = Bcfg2.Options.OptionParser(optinfo)
+ setup.parse(sys.argv[1:])
- def _probe_failure(self, probename, msg):
- """ handle failure of a probe in the way the user wants us to
- (exit or continue) """
- message = "Failed to execute probe %s: %s" % (probename, msg)
- if self.setup['probe_exit']:
- self.fatal_error(message)
- else:
- self.logger.error(message)
-
- def run_probe(self, probe):
- """Execute probe."""
- name = probe.get('name')
- self.logger.info("Running probe %s" % name)
- ret = Bcfg2.Client.XML.Element("probe-data",
- name=name,
- source=probe.get('source'))
- try:
- scripthandle, scriptname = tempfile.mkstemp()
- script = os.fdopen(scripthandle, 'w')
- try:
- script.write("#!%s\n" %
- (probe.attrib.get('interpreter', '/bin/sh')))
- script.write(probe.text)
- script.close()
- os.chmod(scriptname,
- stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH |
- stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH |
- stat.S_IWUSR) # 0755
- proc = Popen(scriptname, stdin=PIPE, stdout=PIPE, stderr=PIPE)
- ret.text, err = proc.communicate()
- rv = proc.wait()
- if err:
- self.logger.warning("Probe %s has error output: %s" %
- (name, err))
- if rv:
- self._probe_failure(name, "Return value %s" % rv)
- self.logger.info("Probe %s has result:" % name)
- self.logger.info(ret.text)
- finally:
- os.unlink(scriptname)
- except: # pylint: disable=W0702
- self._probe_failure(name, sys.exc_info()[1])
- return ret
-
- def fatal_error(self, message):
- """Signal a fatal error."""
- self.logger.error("Fatal error: %s" % (message))
+ if setup['args']:
+ print("Bcfg2 takes no arguments, only options")
+ print(setup.buildHelpMessage())
raise SystemExit(1)
- @property
- def proxy(self):
- """ get an XML-RPC proxy to the server """
- if self._proxy is None:
- self._proxy = Bcfg2.Proxy.ComponentProxy(
- self.setup['server'],
- self.setup['user'],
- self.setup['password'],
- key=self.setup['key'],
- cert=self.setup['certificate'],
- ca=self.setup['ca'],
- allowedServerCNs=self.setup['serverCN'],
- timeout=self.setup['timeout'],
- retries=int(self.setup['retries']),
- delay=int(self.setup['retry_delay']))
- return self._proxy
-
- def run_probes(self, times=None):
- """ run probes and upload probe data """
- if times is None:
- times = dict()
-
- try:
- probes = Bcfg2.Client.XML.XML(str(self.proxy.GetProbes()))
- except (Bcfg2.Proxy.ProxyError,
- Bcfg2.Proxy.CertificateError,
- socket.gaierror,
- socket.error):
- err = sys.exc_info()[1]
- self.fatal_error("Failed to download probes from bcfg2: %s" % err)
- except Bcfg2.Client.XML.ParseError:
- err = sys.exc_info()[1]
- self.fatal_error("Server returned invalid probe requests: %s" %
- err)
-
- times['probe_download'] = time.time()
-
- # execute probes
- probedata = Bcfg2.Client.XML.Element("ProbeData")
- for probe in probes.findall(".//probe"):
- probedata.append(self.run_probe(probe))
-
- if len(probes.findall(".//probe")) > 0:
- try:
- # upload probe responses
- self.proxy.RecvProbeData(Bcfg2.Client.XML.tostring(
- probedata,
- xml_declaration=False).decode('UTF-8'))
- except Bcfg2.Proxy.ProxyError:
- err = sys.exc_info()[1]
- self.fatal_error("Failed to upload probe data: %s" % err)
-
- times['probe_upload'] = time.time()
-
- def get_config(self, times=None):
- """ load the configuration, either from the cached
- configuration file (-f), or from the server """
- if times is None:
- times = dict()
-
- if self.setup['file']:
- # read config from file
- try:
- self.logger.debug("Reading cached configuration from %s" %
- self.setup['file'])
- return open(self.setup['file'], 'r').read()
- except IOError:
- self.fatal_error("Failed to read cached configuration from: %s"
- % (self.setup['file']))
- else:
- # retrieve config from server
- if self.setup['profile']:
- try:
- self.proxy.AssertProfile(self.setup['profile'])
- except Bcfg2.Proxy.ProxyError:
- err = sys.exc_info()[1]
- self.fatal_error("Failed to set client profile: %s" % err)
-
- try:
- self.proxy.DeclareVersion(__version__)
- except xmlrpclib.Fault:
- err = sys.exc_info()[1]
- if (err.faultCode == xmlrpclib.METHOD_NOT_FOUND or
- (err.faultCode == 7 and
- err.faultString.startswith("Unknown method"))):
- self.logger.debug("Server does not support declaring "
- "client version")
- else:
- self.logger.error("Failed to declare version: %s" % err)
- except (Bcfg2.Proxy.ProxyError,
- Bcfg2.Proxy.CertificateError,
- socket.gaierror,
- socket.error):
- err = sys.exc_info()[1]
- self.logger.error("Failed to declare version: %s" % err)
-
- self.run_probes(times=times)
-
- if self.setup['decision'] in ['whitelist', 'blacklist']:
- try:
- self.setup['decision_list'] = \
- self.proxy.GetDecisionList(self.setup['decision'])
- self.logger.info("Got decision list from server:")
- self.logger.info(self.setup['decision_list'])
- except Bcfg2.Proxy.ProxyError:
- err = sys.exc_info()[1]
- self.fatal_error("Failed to get decision list: %s" % err)
-
- try:
- rawconfig = self.proxy.GetConfig().encode('UTF-8')
- except Bcfg2.Proxy.ProxyError:
- err = sys.exc_info()[1]
- self.fatal_error("Failed to download configuration from "
- "Bcfg2: %s" % err)
-
- times['config_download'] = time.time()
- return rawconfig
-
- def run(self):
- """Perform client execution phase."""
- times = {}
-
- # begin configuration
- times['start'] = time.time()
-
- self.logger.info("Starting Bcfg2 client run at %s" % times['start'])
-
- rawconfig = self.get_config(times=times)
-
- if self.setup['cache']:
- try:
- open(self.setup['cache'], 'w').write(rawconfig)
- os.chmod(self.setup['cache'], 33152)
- except IOError:
- self.logger.warning("Failed to write config cache file %s" %
- (self.setup['cache']))
- times['caching'] = time.time()
-
- try:
- self.config = Bcfg2.Client.XML.XML(rawconfig)
- 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)
-
- times['config_parse'] = time.time()
-
- if self.config.tag == 'error':
- self.fatal_error("Server error: %s" % (self.config.text))
- return(1)
-
- if self.setup['bundle_quick']:
- newconfig = Bcfg2.Client.XML.XML('<Configuration/>')
- for bundle in self.config.getchildren():
- if (bundle.tag == 'Bundle' and
- ((self.setup['bundle'] and
- bundle.get('name') in self.setup['bundle']) or
- (self.setup['skipbundle'] and
- bundle.get('name') not in self.setup['skipbundle']))):
- newconfig.append(bundle)
- self.config = newconfig
-
- self.tools = Bcfg2.Client.Frame.Frame(self.config,
- self.setup,
- times, self.setup['drivers'],
- self.setup['dryrun'])
-
- if not self.setup['omit_lock_check']:
- #check lock here
- try:
- lockfile = open(self.setup['lockfile'], 'w')
- try:
- fcntl.lockf(lockfile.fileno(),
- 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" %
- Bcfg2.Options.OMIT_LOCK_CHECK.cmd)
- except: # pylint: disable=W0702
- lockfile = None
- self.logger.error("Failed to open lockfile")
- # execute the said configuration
- self.tools.Execute()
-
- if not self.setup['omit_lock_check']:
- # unlock here
- if lockfile:
- try:
- fcntl.lockf(lockfile.fileno(), fcntl.LOCK_UN)
- os.remove(self.setup['lockfile'])
- except OSError:
- self.logger.error("Failed to unlock lockfile %s" %
- lockfile.name)
-
- if not self.setup['file'] and not self.setup['bundle_quick']:
- # upload statistics
- feedback = self.tools.GenerateStats()
-
- try:
- self.proxy.RecvStats(Bcfg2.Client.XML.tostring(
- feedback,
- xml_declaration=False).decode('UTF-8'))
- except Bcfg2.Proxy.ProxyError:
- err = sys.exc_info()[1]
- self.logger.error("Failed to upload configuration statistics: "
- "%s" % err)
- raise SystemExit(2)
-
- self.logger.info("Finished Bcfg2 client run at %s" % time.time())
-
+ signal.signal(signal.SIGINT, cb_sigint_handler)
+ return Client(setup).run()
if __name__ == '__main__':
- signal.signal(signal.SIGINT, cb_sigint_handler)
- Client().run()
+ sys.exit(main())
diff --git a/src/sbin/bcfg2-info b/src/sbin/bcfg2-info
index d6d529dec..4c5d8f785 100755
--- a/src/sbin/bcfg2-info
+++ b/src/sbin/bcfg2-info
@@ -733,7 +733,7 @@ Bcfg2 client itself.""")
def _run(self):
pass
-
+
def _block(self):
pass