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.

https://fedorahosted.org/freeipa/ticket/4657

Reviewed-By: Martin Basti <mbasti@redhat.com>
This commit is contained in:
Petr Spacek
2015-06-26 17:39:47 +02:00
committed by Tomas Babej
parent c37e83f4b3
commit 68d0f641ba

View File

@@ -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,36 +348,40 @@ 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 + '\n')
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()
@@ -384,13 +391,17 @@ def cmd2ods_zone_name(cmd):
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())