summaryrefslogtreecommitdiffstats
path: root/src/sbin
diff options
context:
space:
mode:
authorJoey Hagedorn <hagedorn@mcs.anl.gov>2007-07-19 18:54:02 +0000
committerJoey Hagedorn <hagedorn@mcs.anl.gov>2007-07-19 18:54:02 +0000
commit59635c22773a8a7b26c7c27891e999a3f71bbd1a (patch)
tree212575b5c0d8afe4461277a3d233e6f11a02a0ce /src/sbin
parenta242c972022895986e5b067b12b4b41b17ffa9e2 (diff)
downloadbcfg2-59635c22773a8a7b26c7c27891e999a3f71bbd1a.tar.gz
bcfg2-59635c22773a8a7b26c7c27891e999a3f71bbd1a.tar.bz2
bcfg2-59635c22773a8a7b26c7c27891e999a3f71bbd1a.zip
merging back in xmlrpc branch for agent-mode support
git-svn-id: https://svn.mcs.anl.gov/repos/bcfg/trunk/bcfg2@3505 ce84e21b-d406-0410-9b95-82705330c041
Diffstat (limited to 'src/sbin')
-rwxr-xr-xsrc/sbin/bcfg2145
-rwxr-xr-xsrc/sbin/bcfg2-remote55
2 files changed, 196 insertions, 4 deletions
diff --git a/src/sbin/bcfg2 b/src/sbin/bcfg2
index 262cdc8b9..333048535 100755
--- a/src/sbin/bcfg2
+++ b/src/sbin/bcfg2
@@ -7,6 +7,7 @@ import getopt
import logging
import os
import signal
+import socket
import sys
import tempfile
import time
@@ -15,6 +16,9 @@ import Bcfg2.Options
import Bcfg2.Client.XML
import Bcfg2.Client.Frame
import Bcfg2.Client.Tools
+from Bcfg2.Component import *
+from Bcfg2.tlslite.Checker import Checker
+from Bcfg2.tlslite.errors import *
try:
import Bcfg2.Client.Proxy
@@ -83,6 +87,12 @@ class Client:
False, ('communication', 'retries'), '3', False),
'kevlar': (('-k', False, "run in kevlar (bulletproof) mode"),
False, False, False, True),
+ 'agent': (('-A', False, "run in agent (continuous) mode, wait for reconfigure command from server"),
+ False, False, False, True),
+ 'agent-port': (('-g', '<agent tcp port>', 'the port on which to bind for agent mode'),
+ False, ('communication', 'agent-port'), '6789', False),
+ 'key': (('-K', '<client key file>', 'ssl cert + private key for agent mode xmlrpc server'),
+ False, ('communication', 'key'), False, False),
}
optparser = Bcfg2.Options.OptionParser('bcfg2', optinfo)
@@ -111,6 +121,15 @@ class Client:
if (self.setup["file"] != False) and (self.setup["cache"] != False):
print "cannot use -f and -c together"
raise SystemExit(1)
+ if (self.setup["agent"] != False) and (self.setup["interactive"] != False):
+ print "cannot use -A and -I together"
+ raise SystemExit(1)
+ if (self.setup["agent"] and not self.setup["fingerprint"]):
+ print "Agent mode requires specification of x509 fingerprint"
+ raise SystemExit(1)
+ if (self.setup["agent"] and not self.setup["key"]):
+ print "Agent mode requires specification of ssl cert + key file"
+ raise SystemExit(1)
def run_probe(self, probe):
'''Execute probe'''
@@ -137,8 +156,11 @@ class Client:
def fatal_error(self, message):
'''Signal a fatal error'''
self.logger.error("Fatal error: %s" % (message))
- raise SystemExit(1)
-
+ if not self.setup["agent"]:
+ raise SystemExit(1)
+ else:
+ self.logger.error("Continuing...")
+
def run(self):
''' Perform client execution phase '''
times = {}
@@ -157,18 +179,21 @@ class Client:
except IOError:
self.fatal_error("failed to read cached configuration from: %s"
% (self.setup['file']))
+ return(1)
else:
# retrieve config from server
try:
proxy = Bcfg2.Client.Proxy.bcfg2(self.setup)
except:
self.fatal_error("failed to instantiate proxy to server")
+ return(1)
if self.setup['profile']:
try:
proxy.AssertProfile(self.setup['profile'])
except xmlrpclib.Fault:
self.fatal_error("Failed to set client profile")
+ return(1)
try:
probe_data = proxy.GetProbes()
@@ -185,6 +210,7 @@ class Client:
self.fatal_error(
"server returned invalid probe requests: %s" %
(syntax_error))
+ return(1)
# execute probes
try:
@@ -227,13 +253,17 @@ class Client:
except Bcfg2.Client.XML.ParseError, syntax_error:
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)
- self.tools = Bcfg2.Client.Frame.Frame(self.config, self.setup, times)
+ self.tools = Bcfg2.Client.Frame.Frame(self.config,
+ self.setup,
+ times)
self.tools.Execute()
@@ -247,7 +277,114 @@ class Client:
self.logger.error("Failed to upload configuration statistics")
raise SystemExit(2)
+class FingerCheck(object):
+ def __init__(self, fprint):
+ self.fingerprint = fprint
+ self.logger = logging.getLogger('checker')
+
+ def __call__(self, connection):
+ if connection._client:
+ chain = connection.session.serverCertChain
+ else:
+ chain = connection.session.clientCertChain
+
+ if chain == None:
+ self.logger.error("Fingerprint authentication error")
+ raise TLSNoAuthenticationError()
+ if chain.getFingerprint() != self.fingerprint:
+ self.logger.error("Got connection with bad fingerprint %s" \
+ % (chain.getFingerprint()))
+ raise TLSFingerprintError(\
+ "X.509 fingerprint mismatch: %s, %s" % \
+ (chain.getFingerprint(), self.fingerprint))
+
+class Agent(Bcfg2.Component.Component):
+ """The Bcfg2 Agent component providing XML-RPC access to 'run'"""
+ __name__ = 'bcfg2-agent'
+ __implementation__ = 'bcfg2-agent'
+
+ def __init__(self, client):
+ # need to get addr
+ self.setup = client.setup
+ self.shut = False
+ signal.signal(signal.SIGINT, self.start_shutdown)
+ signal.signal(signal.SIGTERM, self.start_shutdown)
+ self.logger = logging.getLogger('Agent')
+
+ self.static = True
+
+ if self.setup["agent-port"]:
+ port = int(self.setup["agent-port"])
+ elif self.setup["server"]:
+ port = int(self.setup["server"].split(':')[1])
+ else:
+ print "port or server URL not specified"
+ raise SystemExit, 1
+
+ location = (socket.gethostname(), port)
+
+ keyfile = self.setup["key"]
+ self.password = self.setup["password"]
+
+ try:
+ TLSServer.__init__(self,
+ location,
+ keyfile,
+ CobaltXMLRPCRequestHandler,
+ FingerCheck(self.setup["fingerprint"]),
+ reqCert=True)
+ except socket.error:
+ self.logger.error("Failed to bind to socket")
+ raise ComponentInitError
+ except ComponentKeyError:
+ self.logger.error("Failed to parse key" % (keyfile))
+ raise ComponentInitError
+ except:
+ self.logger.error("Failed to load ssl key %s" % (keyfile), exc_info=1)
+ raise ComponentInitError
+ try:
+ SimpleXMLRPCServer.SimpleXMLRPCDispatcher.__init__(self)
+ except TypeError:
+ SimpleXMLRPCServer.SimpleXMLRPCDispatcher.__init__(self, False, None)
+ self.logRequests = 0
+ self.port = self.socket.getsockname()[1]
+ self.url = "https://%s:%s" % (socket.gethostname(), self.port)
+ self.logger.info("Bound to port %s" % self.port)
+ self.funcs.update({'system.listMethods':self.addr_system_listMethods})
+ self.atime = 0
+ self.client = client
+ self.funcs.update({
+ "run": self.run,
+ })
+
+ def run(self, address):
+ try:
+ os.waitpid(-1, os.WNOHANG)
+ except:
+ pass
+ self.logger.info("Got run request from %s" % (address[0]))
+ if os.fork():
+ return True
+ else:
+ try:
+ self.client.run()
+ except SystemExit:
+ self.logger.error("Client failed to execute")
+ self.shut = True
+ return False
+
if __name__ == '__main__':
signal.signal(signal.SIGINT, cb_sigint_handler)
client = Client()
- client.run()
+ spid = os.getpid()
+ if client.setup["agent"]:
+ agent = Agent(client)
+ while not agent.shut:
+ try:
+ agent.serve_forever()
+ except:
+ critical_error('error in service loop')
+ if os.getpid() == spid:
+ print("Shutting down")
+ else:
+ client.run()
diff --git a/src/sbin/bcfg2-remote b/src/sbin/bcfg2-remote
new file mode 100755
index 000000000..4b45965c6
--- /dev/null
+++ b/src/sbin/bcfg2-remote
@@ -0,0 +1,55 @@
+#!/usr/bin/env python
+__revision__ = '$Revision$'
+
+from Bcfg2.tlslite.api import parsePEMKey, X509, X509CertChain
+from xmlrpclib import ServerProxy
+from Bcfg2.tlslite.integration.XMLRPCTransport import XMLRPCTransport
+import Bcfg2.Options, Bcfg2.Logging, logging, socket
+
+if __name__ == '__main__':
+ opts = {
+ 'agent-port': (('-p', '<agent tcp port>', 'agent TCP port'),
+ False, ('communication', 'agent-port'),
+ '6789', False),
+ 'host': (('-H', '<agent host>', 'agent host'),
+ False, False, False, False),
+ 'setup': (('-C', '<configfile>', "config file path"),
+ False, False, '/etc/bcfg2.conf', False),
+ 'key': (('-k', '<ssl key>', 'ssl key path'),
+ False, ('communication', 'key'), False, False),
+ 'debug': (('-d', '<debug level>', 'debug level (0-40)'),
+ False, False, 0, False),
+ }
+ optparser = Bcfg2.Options.OptionParser('bcfg2', opts)
+ setup = optparser.parse()
+ Bcfg2.Logging.setup_logging('bcfg2-remote',
+ to_syslog=False,
+ level=int(setup['debug']))
+ logger = logging.getLogger('bcfg2-remote')
+ if not setup['host']:
+ logger.error("-H option is required")
+ logger.error(optparser.helpmsg)
+ raise SystemExit(1)
+ s = open(setup['key']).read()
+ x509 = X509()
+ x509.parse(s)
+ certChain = X509CertChain([x509])
+ #s = open("/etc/bcfg2.key").read()
+ privateKey = parsePEMKey(s, private=True)
+
+ transport = XMLRPCTransport(certChain=certChain,
+ privateKey=privateKey)
+ host = setup['host']
+ port = setup['agent-port']
+ server = ServerProxy("https://%s:%s" % (host, port), transport)
+
+ try:
+ result = server.run()
+ except socket.error, serr:
+ if serr.args[0] == 111:
+ logger.error("Failed to connect to client %s" % host)
+ elif serr.args[0] == 32:
+ logger.error("Connection to client %s dropped; authentication failure?" % host)
+ else:
+ logger.error("Got unexpected socket error %d" % serr.args[0])
+ raise SystemExit(1)