├── .gitignore ├── LICENSE.txt ├── MANIFEST.in ├── README.md ├── sdnotify └── __init__.py ├── setup.cfg └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | MANIFEST 11 | .Python 12 | env/ 13 | build/ 14 | develop-eggs/ 15 | dist/ 16 | downloads/ 17 | eggs/ 18 | .eggs/ 19 | lib/ 20 | lib64/ 21 | parts/ 22 | sdist/ 23 | var/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | 28 | 29 | *~ 30 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Brett Bethke 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | #License 2 | include LICENSE.txt 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # systemd Service Notification 2 | 3 | This is a pure Python implementation of the 4 | [`systemd`](http://www.freedesktop.org/wiki/Software/systemd/) 5 | [`sd_notify`](http://www.freedesktop.org/software/systemd/man/sd_notify.html) 6 | protocol. This protocol can be used to inform `systemd` about service start-up 7 | completion, watchdog events, and other service status changes. Thus, this 8 | package can be used to write system services in Python that play nicely with 9 | `systemd`. `sdnotify` is compatible with both Python 2 and Python 3. 10 | 11 | Normally the `SystemdNotifier.notify` method silently ignores exceptions (for example, if the 12 | systemd notification socket is not available) to allow applications to 13 | function on non-systemd based systems. However, setting `debug=True` will 14 | cause this method to raise any exceptions generated to the caller, to 15 | aid in debugging. 16 | 17 | # Installation 18 | 19 | `pip install sdnotify` 20 | 21 | # Example Usage 22 | 23 | This is an example of a simple Python service that informs `systemd` when its 24 | startup sequence is complete. It also sends periodic status updates to `systemd`, 25 | which can be viewed with `systemctl status test`. 26 | 27 | ## `test.py` 28 | ```python 29 | import sdnotify 30 | import time 31 | 32 | print("Test starting up...") 33 | # In a real service, this is where you'd do real startup tasks 34 | # like opening listening sockets, connecting to a database, etc... 35 | time.sleep(10) 36 | print("Test startup finished") 37 | 38 | # Inform systemd that we've finished our startup sequence... 39 | n = sdnotify.SystemdNotifier() 40 | n.notify("READY=1") 41 | 42 | count = 1 43 | while True: 44 | print("Running... {}".format(count)) 45 | n.notify("STATUS=Count is {}".format(count)) 46 | count += 1 47 | time.sleep(2) 48 | ``` 49 | 50 | ## `test.service` 51 | 52 | [Unit] 53 | Description=A test service written in Python 54 | 55 | [Service] 56 | # Note: setting PYTHONUNBUFFERED is necessary to see the output of this service in the journal 57 | # See https://docs.python.org/2/using/cmdline.html#envvar-PYTHONUNBUFFERED 58 | Environment=PYTHONUNBUFFERED=true 59 | 60 | # Adjust this line to the correct path to test.py 61 | ExecStart=/usr/bin/python /path/to/test.py 62 | 63 | # Note that we use Type=notify here since test.py will send "READY=1" 64 | # when it's finished starting up 65 | Type=notify 66 | -------------------------------------------------------------------------------- /sdnotify/__init__.py: -------------------------------------------------------------------------------- 1 | import socket 2 | import os 3 | import sys 4 | 5 | __version__ = "0.3.2" 6 | 7 | # Byte conversion utility for compatibility between 8 | # Python 2 and 3. 9 | # http://python3porting.com/problems.html#nicer-solutions 10 | if sys.version_info < (3,): 11 | def _b(x): 12 | return x 13 | else: 14 | import codecs 15 | def _b(x): 16 | return codecs.latin_1_encode(x)[0] 17 | 18 | 19 | class SystemdNotifier: 20 | """This class holds a connection to the systemd notification socket 21 | and can be used to send messages to systemd using its notify method.""" 22 | 23 | def __init__(self, debug=False): 24 | """Instantiate a new notifier object. This will initiate a connection 25 | to the systemd notification socket. 26 | 27 | Normally this method silently ignores exceptions (for example, if the 28 | systemd notification socket is not available) to allow applications to 29 | function on non-systemd based systems. However, setting debug=True will 30 | cause this method to raise any exceptions generated to the caller, to 31 | aid in debugging. 32 | """ 33 | self.debug = debug 34 | try: 35 | self.socket = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM) 36 | addr = os.getenv('NOTIFY_SOCKET') 37 | if addr[0] == '@': 38 | addr = '\0' + addr[1:] 39 | self.socket.connect(addr) 40 | except Exception: 41 | self.socket = None 42 | if self.debug: 43 | raise 44 | 45 | def notify(self, state): 46 | """Send a notification to systemd. state is a string; see 47 | the man page of sd_notify (http://www.freedesktop.org/software/systemd/man/sd_notify.html) 48 | for a description of the allowable values. 49 | 50 | Normally this method silently ignores exceptions (for example, if the 51 | systemd notification socket is not available) to allow applications to 52 | function on non-systemd based systems. However, setting debug=True will 53 | cause this method to raise any exceptions generated to the caller, to 54 | aid in debugging.""" 55 | try: 56 | self.socket.sendall(_b(state)) 57 | except Exception: 58 | if self.debug: 59 | raise 60 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | description-file = README.md -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup 2 | 3 | VERSION='0.3.2' 4 | 5 | setup( 6 | name = 'sdnotify', 7 | packages = ['sdnotify'], 8 | version = VERSION, 9 | description = 'A pure Python implementation of systemd\'s service notification protocol (sd_notify)', 10 | author = 'Brett Bethke', 11 | author_email = 'bbethke@gmail.com', 12 | url = 'https://github.com/bb4242/sdnotify', 13 | download_url = 'https://github.com/bb4242/sdnotify/tarball/v{}'.format(VERSION), 14 | keywords = ['systemd'], 15 | classifiers = [ 16 | "Programming Language :: Python", 17 | "Programming Language :: Python :: 3", 18 | "Development Status :: 4 - Beta", 19 | "Intended Audience :: Developers", 20 | "License :: OSI Approved :: MIT License", 21 | "Operating System :: POSIX :: Linux", 22 | "Topic :: Software Development :: Libraries :: Python Modules", 23 | ], 24 | long_description = """\ 25 | systemd Service Notification 26 | 27 | This is a pure Python implementation of the systemd sd_notify protocol. This protocol can be used to inform systemd about service start-up completion, watchdog events, and other service status changes. Thus, this package can be used to write system services in Python that play nicely with systemd. sdnotify is compatible with both Python 2 and Python 3. 28 | """ 29 | ) 30 | --------------------------------------------------------------------------------