Martin Peřina has uploaded a new change for review. Change subject: tools: Adds support to notify systemd using sd_notify ......................................................................
tools: Adds support to notify systemd using sd_notify Adds support to notifier service to notify systemd about service startup success/error using sd_notify daemon. Change-Id: Ie62a4ba5a837bcaf216ace9870e212a7151aa8bc Bug-Url: https://bugzilla.redhat.com/989382 Signed-off-by: Martin Perina <mper...@redhat.com> --- A packaging/pythonlib/ovirt_engine/sdnotify.py M packaging/pythonlib/ovirt_engine/service.py M packaging/services/ovirt-engine-notifier/ovirt-engine-notifier.py M packaging/services/ovirt-engine-notifier/ovirt-engine-notifier.systemd.in 4 files changed, 140 insertions(+), 9 deletions(-) git pull ssh://gerrit.ovirt.org:29418/ovirt-engine refs/changes/30/22630/1 diff --git a/packaging/pythonlib/ovirt_engine/sdnotify.py b/packaging/pythonlib/ovirt_engine/sdnotify.py new file mode 100644 index 0000000..3ba1f35 --- /dev/null +++ b/packaging/pythonlib/ovirt_engine/sdnotify.py @@ -0,0 +1,81 @@ +# +# Copyright 2013 Red Hat +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +import os +import socket + + +from . import base +from . import util + + +@util.export +class Notifier(base.Base): + """Sends messages to systemd about service startup success or error""" + + def __init__(self, socket=None): + super(Notifier, self).__init__() + self._socket = socket + if not self._socket: + self._socket = os.environ.get('NOTIFY_SOCKET') + + def sendDict(self, state): + """Converts state defined as dict to string and sends it to systemd""" + return self.sendStr( + '\n'.join(['{0}={1}'.format(k, v) for (k, v) in state.iteritems()]) + ) + + def sendStr(self, state): + """Sends state defined as string to systemd. Return True if state was + sent successfully, otherwise False""" + + if self._socket[0] not in ('@', '/') or len(self._socket) == 1: + raise RuntimeError( + "Invalid sd_notify socket '%s'" % self._socket + ) + + if self._socket[0] == '@': + self._socket = '\0' + self._socket[1:] + + self.logger.debug( + "Using socket '%s' to notify systemd", + self._socket, + ) + + result = True + s = None + try: + self.logger.debug( + "Sending '%s' to systemd", + state, + ) + + s = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM) + if s.sendto(state, self._socket) < 1: + result = False + except socket.error as e: + self.logger.error( + "Cannot send '%s' to systemd, error '%s'", + state, + e, + ) + finally: + if s is not None: + s.close() + return result + + +# vim: expandtab tabstop=4 shiftwidth=4 diff --git a/packaging/pythonlib/ovirt_engine/service.py b/packaging/pythonlib/ovirt_engine/service.py index b25d58b..a91917c 100644 --- a/packaging/pythonlib/ovirt_engine/service.py +++ b/packaging/pythonlib/ovirt_engine/service.py @@ -292,6 +292,8 @@ close_fds=True, ) + self.postDaemonExec(proc=p) + self.logger.debug( 'waiting for termination of pid=%s', p.pid, @@ -414,12 +416,8 @@ self.logger.debug('daemon return') - def run(self): - self.logger.debug('startup args=%s', sys.argv) - - parser = optparse.OptionParser( - usage=_('usage: %prog [options] start'), - ) + def addArgs(self, parser): + """Registers valid command line arguments""" parser.add_option( '-d', '--debug', dest='debug', @@ -448,6 +446,14 @@ default=False, help=_('Redirect output of daemon'), ) + + def run(self): + self.logger.debug('startup args=%s', sys.argv) + + parser = optparse.OptionParser( + usage=_('usage: %prog [options] start'), + ) + self.addArgs(parser) (self._options, args) = parser.parse_args() if self._options.debug: @@ -488,6 +494,7 @@ ) ) self.logger.debug('exception', exc_info=True) + self.onDaemonException(e) sys.exit(1) else: sys.exit(0) @@ -506,6 +513,15 @@ """Called prior to daemon execution""" pass + def postDaemonExec(self, proc): + """Called after daemon subprocess execution, proc identifies daemon + subprocess.""" + pass + + def onDaemonException(self, exception): + """Called if exception is raised during daemon execution""" + pass + def daemonContext(self): """Daemon logic Called within daemon context diff --git a/packaging/services/ovirt-engine-notifier/ovirt-engine-notifier.py b/packaging/services/ovirt-engine-notifier/ovirt-engine-notifier.py index cd7089b..9f521c1 100755 --- a/packaging/services/ovirt-engine-notifier/ovirt-engine-notifier.py +++ b/packaging/services/ovirt-engine-notifier/ovirt-engine-notifier.py @@ -26,6 +26,7 @@ from ovirt_engine import configfile +from ovirt_engine import sdnotify from ovirt_engine import service from ovirt_engine import java @@ -88,8 +89,18 @@ mustExist=False, ) - def daemonSetup(self): + def addArgs(self, parser): + """Adds argument to enable sd_notify functionality""" + super(Daemon, self).addArgs(parser) + parser.add_option( + '--notify', + dest='notify', + action='store_true', + default=False, + help=_('Enables notification of daemon startup success/error'), + ) + def daemonSetup(self): if os.geteuid() == 0: raise RuntimeError( _('This service cannot be executed as root') @@ -203,6 +214,28 @@ if proc.returncode != 0: raise RuntimeError('Error validating notifier configuration') + def postDaemonExec(self, proc): + """Notifies systemd about daemon startup""" + if self._options.notify: + exitCode = proc.poll() + if exitCode is None: + sdnotify.Notifier().sendDict( + state={ + 'READY': '1', + 'STATUS': 'Notifier daemon executed', + } + ) + + def onDaemonException(self, exception): + """Called if exception is raised during daemon execution""" + if self._options.notify: + sdnotify.Notifier().sendDict( + state={ + 'ERRNO': '1', + 'STATUS': 'Failed to start notifier', + } + ) + if __name__ == '__main__': service.setupLogger() diff --git a/packaging/services/ovirt-engine-notifier/ovirt-engine-notifier.systemd.in b/packaging/services/ovirt-engine-notifier/ovirt-engine-notifier.systemd.in index 9d53b2f..158132f 100644 --- a/packaging/services/ovirt-engine-notifier/ovirt-engine-notifier.systemd.in +++ b/packaging/services/ovirt-engine-notifier/ovirt-engine-notifier.systemd.in @@ -3,10 +3,11 @@ After=network.service postgresql.service [Service] -Type=simple +Type=notify +NotifyAccess=main User=@ENGINE_USER@ Group=@ENGINE_GROUP@ -ExecStart=@ENGINE_USR@/services/ovirt-engine-notifier/ovirt-engine-notifier.py --redirect-output $EXTRA_ARGS start +ExecStart=@ENGINE_USR@/services/ovirt-engine-notifier/ovirt-engine-notifier.py --redirect-output --notify $EXTRA_ARGS start EnvironmentFile=-/etc/sysconfig/ovirt-engine-notifier [Install] -- To view, visit http://gerrit.ovirt.org/22630 To unsubscribe, visit http://gerrit.ovirt.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ie62a4ba5a837bcaf216ace9870e212a7151aa8bc Gerrit-PatchSet: 1 Gerrit-Project: ovirt-engine Gerrit-Branch: master Gerrit-Owner: Martin Peřina <mper...@redhat.com> _______________________________________________ Engine-patches mailing list Engine-patches@ovirt.org http://lists.ovirt.org/mailman/listinfo/engine-patches