Hello,

DNSSEC: Accept ipa-ods-exporter commands from command line.

Previously only systemd socket activation was supported.
Ability to call the command directly is handy in special cases,
e.g. for debugging or moving key master role from one server to another.

-- 
Petr^2 Spacek
From 7381ae8abefab20f975cd64b93161c1c546d4a7f Mon Sep 17 00:00:00 2001
From: Petr Spacek <pspa...@redhat.com>
Date: Fri, 26 Jun 2015 17:39:47 +0200
Subject: [PATCH] DNSSEC: Accept ipa-ods-exporter commands from command line.

Previously only systemd socket activation was supported.
Ability to call the command directly is handy in special cases,
e.g. for debugging or moving key master role from one server to another.
---
 daemons/dnssec/ipa-ods-exporter | 88 ++++++++++++++++++++++++++---------------
 1 file changed, 56 insertions(+), 32 deletions(-)

diff --git a/daemons/dnssec/ipa-ods-exporter b/daemons/dnssec/ipa-ods-exporter
index 913b418af2806e2660a7db221e06394b501bbb18..63a83f2e785371e2530be837941000a8051347f9 100755
--- a/daemons/dnssec/ipa-ods-exporter
+++ b/daemons/dnssec/ipa-ods-exporter
@@ -9,6 +9,9 @@ This program uses the same socket and protocol as original signerd and should
 be activated via systemd socket activation using "ods-signer" command line
 utility.
 
+Alternativelly, it can be called directly and a command can be supplied as
+first command line argument.
+
 Purpose of this replacement is to upload keys generated by OpenDNSSEC to LDAP.
 """
 
@@ -334,7 +337,7 @@ def hex_set(s):
         out.add("0x%s" % hexlify(i))
     return out
 
-def receive_zone_name(log):
+def receive_systemd_command(log):
     fds = systemd.daemon.listen_fds()
     if len(fds) != 1:
         raise KeyError('Exactly one socket is expected.')
@@ -345,52 +348,60 @@ def receive_zone_name(log):
     log.debug('accepted new connection %s', repr(conn))
 
     # this implements cmdhandler_handle_cmd() logic
-    cmd = conn.recv(ODS_SE_MAXLINE)
-    cmd = cmd.strip()
+    cmd = conn.recv(ODS_SE_MAXLINE).strip()
+    log.debug('received command "%s" from systemd socket', cmd)
+    return (cmd, conn)
 
-    try:
-        if cmd == 'ipa-hsm-update':
-            msg = 'HSM synchronization finished, exiting.'
-            conn.send('%s\n' % msg)
-            log.info(msg)
-            sys.exit(0)
+def parse_command(cmd):
+    """Parse command to (exit code, message, zone_name) tuple.
 
-        elif not cmd.startswith('update '):
-            conn.send('Command "%s" is not supported by IPA; ' \
-                      'HSM synchronization was finished and the command ' \
-                      'will be ignored.\n' % cmd)
-            log.info('Ignoring unsupported command "%s".', cmd)
-            sys.exit(0)
+    Exit code None means that execution should continue.
+    """
+    if cmd == 'ipa-hsm-update':
+        return (0,
+                'HSM synchronization finished, exiting.',
+                None)
 
-        else:
-            zone_name = cmd2ods_zone_name(cmd)
-            conn.send('Update request for zone "%s" queued.\n' % zone_name)
-            log.info('Processing command: "%s"', cmd)
+    elif not cmd.startswith('update '):
+        return (0,
+                'Command "%s" is not supported by IPA; '
+                'HSM synchronization was finished and the command '
+                'will be ignored.\n' % cmd,
+                None)
 
-    finally:
+    else:
+        zone_name = cmd2ods_zone_name(cmd)
+        return (None,
+                'Update request for zone "%s" queued.\n' % zone_name,
+                zone_name)
+
+def send_systemd_reply(conn, reply):
         # Reply & close connection early.
         # This is necessary to let Enforcer to unlock the ODS DB.
+        conn.send(reply)
         conn.shutdown(socket.SHUT_RDWR)
         conn.close()
 
-    return zone_name
-
 def cmd2ods_zone_name(cmd):
     # ODS stores zone name without trailing period
     zone_name = cmd[7:].strip()
     if len(zone_name) > 1 and zone_name[-1] == '.':
         zone_name = zone_name[:-1]
 
     return zone_name
 
 log = logging.getLogger('root')
-# this service is socket-activated
+# this service is usually socket-activated
 log.addHandler(systemd.journal.JournalHandler())
 log.setLevel(level=logging.DEBUG)
 
-if len(sys.argv) != 1:
+if len(sys.argv) > 2:
     print __doc__
     sys.exit(1)
+# program was likely invoked from console, log to it
+elif len(sys.argv) == 2:
+    console = logging.StreamHandler()
+    log.addHandler(console)
 
 # IPA framework initialization
 ipalib.api.bootstrap(in_server=True, log=None)  # no logging to file
@@ -429,16 +440,29 @@ master2ldap_zone_keys_sync(log, ldapkeydb, localhsm)
 # command receive is delayed so the command will stay in socket queue until
 # the problem with LDAP server or HSM is fixed
 try:
-    zone_name = receive_zone_name(log)
-
+    cmd, conn = receive_systemd_command(log)
+    if len(sys.argv) != 1:
+        log.critical('No additional parameters are accepted when '
+                     'socket activation is used.')
+        sys.exit(1)
 # Handle cases where somebody ran the program without systemd.
 except KeyError as e:
-    print 'HSM (key material) sychronization is finished but ' \
-          'this program should be socket-activated by OpenDNSSEC.'
-    print 'Use "ods-signer" command line utility to synchronize ' \
-          'DNS zone keys and metadata.'
-    print 'Error: %s' % e
-    sys.exit(0)
+    if len(sys.argv) != 2:
+        print(__doc__)
+        print('ERROR: Exactly one parameter or socket activation is required.')
+        sys.exit(1)
+    conn = None
+    cmd = sys.argv[1]
+
+exitcode, msg, zone_name = parse_command(cmd)
+
+if conn:
+    send_systemd_reply(conn, msg)
+if exitcode is not None:
+    log.info(msg)
+    sys.exit(exitcode)
+else:
+    log.debug(msg)
 
 ods_keys = get_ods_keys(zone_name)
 ods_keys_id = set(ods_keys.keys())
-- 
2.1.0

-- 
Manage your subscription for the Freeipa-devel mailing list:
https://www.redhat.com/mailman/listinfo/freeipa-devel
Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code

Reply via email to