aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README3
-rwxr-xr-xexmachina.py111
-rwxr-xr-xtest.py11
3 files changed, 110 insertions, 15 deletions
diff --git a/README b/README
index a4a387b..690bc17 100644
--- a/README
+++ b/README
@@ -11,14 +11,11 @@
Just a first commit...
TODO:
-* export python-augeas API calls in server
-* add /etc/init.d start/stop/status/reset API methods
* re-implement python-augeas methods using API client-side
* use /var/lib/exmachina/<something> as socket instead of /tmp/exmachina.sock?
* check to make sure server is running as root
* check/set permissions on socket after server opens it
* tests and demonstrations
-* fix/remove logging
### Dependancies (server)
diff --git a/exmachina.py b/exmachina.py
index fca499e..cb909ef 100755
--- a/exmachina.py
+++ b/exmachina.py
@@ -9,6 +9,8 @@ import sys
import optparse
import logging
import socket
+import subprocess
+import stat
import bjsonrpc
import bjsonrpc.handlers
@@ -19,26 +21,106 @@ import time # TODO
log = logging.getLogger(__name__)
+def run_service(servicename, action, timeout=10):
+ """This function mostly ripped from StackOverflow:
+ http://stackoverflow.com/questions/1556348/python-run-a-process-with-timeout-and-capture-stdout-stderr-and-exit-status
+ """
+ # ensure service name isn't tricky trick
+ script = "/etc/init.d/" + os.path.split(servicename)[1]
+
+ if not os.path.exists(script):
+ return "ERROR: so such service"
+
+ command_list = [script, action]
+ log.info("running: %s" % command_list)
+ proc = subprocess.Popen(command_list,
+ bufsize=0,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ poll_seconds = .250
+ deadline = time.time() + timeout
+ while time.time() < deadline and proc.poll() == None:
+ time.sleep(poll_seconds)
+
+ if proc.poll() == None:
+ if float(sys.version[:3]) >= 2.6:
+ proc.terminate()
+ raise Exception("Timeout: %s" % command_list)
+
+ stdout, stderr = proc.communicate()
+ return stdout, stderr, proc.returncode
class ExMachinaHandler(bjsonrpc.handlers.BaseHandler):
- def whattime(self):
- print "hup!"
+
+ def _setup(self):
+ self.augeas = augeas.Augeas()
+
+ def test_whattime(self):
+ log.debug("whattime")
return time.time()
- def listfiles(self):
- a = augeas.Augeas()
- return a.match("/files/etc/*")
+ def test_listfiles(self):
+ log.debug("listfiles")
+ return self.augeas.match("/files/etc/*")
+
+ # ------------- Augeas API Passthrough -----------------
+ def augeas_save(self):
+ log.info("augeas: saving config")
+ return self.augeas.save()
+
+ def augeas_set(self, path, value):
+ log.info("augeas: set %s=%s" % (path, value))
+ return self.augeas.set(path.encode('utf-8'),
+ value.encode('utf-8'))
+
+ def augeas_setm(self, base, sub, value):
+ log.info("augeas: setm %s %s = %s" % (base, sub, value))
+ return self.augeas.setm(base.encode('utf-8'),
+ sub.encode('utf-8'),
+ value.encode('utf-8'))
+
+ def augeas_get(self, path):
+ # reduce verbosity
+ log.debug("augeas: get %s" % path)
+ return self.augeas.get(path.encode('utf-8'))
+
+ def augeas_match(self, path):
+ # reduce verbosity
+ log.debug("augeas: match %s" % path)
+ return self.augeas.match("%s" % path.encode('utf-8'))
+
+ def augeas_insert(self, path, label, before=True):
+ log.info("augeas: insert %s=%s" % (path, value))
+ return self.augeas.insert(path.encode('utf-8'),
+ label.encode('utf-8'),
+ before=before)
+
+ def augeas_move(self, src, dst):
+ log.info("augeas: move %s -> %s" % (src, dst))
+ return self.augeas.move(src.encode('utf-8'), dst.encode('utf-8'))
+
+ def augeas_remove(self, path):
+ log.info("augeas: remove %s" % path)
+ return self.augeas.remove(path.encode('utf-8'))
+
+ # ------------- Service Control -----------------
+ def initd_status(self, servicename):
+ return run_service(servicename, "status")
+
+ def initd_start(self, servicename):
+ return run_service(servicename, "start")
+
+ def initd_stop(self, servicename):
+ return run_service(servicename, "stop")
+
+ def initd_restart(self, servicename):
+ return run_service(servicename, "restart")
class ExMachinaClient():
pass #TODO
def run_server(socket_path="/tmp/exmachina.sock"):
# TODO: check for root permissions, warn if not root
- log.info('This is an INFO level message.')
- log.debug('This is a DEBUG level message.')
- log.warn('This is a WARN level message.')
-
- # TODO: if socket file exists, try to delete it
if os.path.exists(socket_path):
os.unlink(socket_path)
@@ -47,6 +129,10 @@ def run_server(socket_path="/tmp/exmachina.sock"):
sock.listen(1)
serv = bjsonrpc.server.Server(sock, handler_factory=ExMachinaHandler)
+
+ # TODO: group permissions only?
+ os.chmod(socket_path, 0777)
+
serv.serve()
# =============================================================================
@@ -69,6 +155,11 @@ def main():
parser.error("Incorrect number of arguments")
log = logging.getLogger()
+ hdlr = logging.StreamHandler()
+ formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
+ hdlr.setFormatter(formatter)
+ log.addHandler(hdlr)
+
if options.verbose:
log.setLevel(logging.DEBUG)
else:
diff --git a/test.py b/test.py
index f6c4de1..b9295b8 100755
--- a/test.py
+++ b/test.py
@@ -18,8 +18,15 @@ def main():
sock.connect(socket_path)
c = bjsonrpc.connection.Connection(sock)
- print c.call.whattime()
- print c.call.listfiles()
+ print "time: %s" % c.call.test_whattime()
+ print "files: %s" % c.call.test_listfiles()
+ print c.call.initd_status("bluetooth")
+ print "/*: %s" % c.call.augeas_match("/*")
+ print "/files/*: %s" % c.call.augeas_match("/files/*")
+ print "/files/etc/*: %s" % c.call.augeas_match("/files/etc/*")
+ print "/augeas/*: %s" % c.call.augeas_match("/augeas/*")
+ print "hostname: %s" % c.call.augeas_get("/files/etc/hostname/*")
+ print "localhost: %s" % c.call.augeas_get("/files/etc/hosts/1/canonical")
if __name__ == '__main__':
main()