The example below creates a Unix Socket server listening on a stream (i.e. SOCK_STREAM
) socket. A similar approach can be followed to
create a UDP server on a datagram (i.e. SOCK_DGRAM
) socket. See man systemd.socket
for details.
Create an simple echo server at /opt/foo/serve.py
.
#!/usr/bin/python
from SocketServer import UnixStreamServer, StreamRequestHandler
import logging
import os
import sys
class Handler(StreamRequestHandler):
def handle(self):
self.data = self.rfile.readline().strip()
logging.info("From <%s>: %s" % (self.client_address, self.data))
self.wfile.write(self.data.upper() + "\r\n")
class Server(UnixStreamServer):
# The constant would be better initialized by a systemd module
SYSTEMD_FIRST_SOCKET_FD = 3
def __init__(self, server_address, handler_cls):
# Invoke base but omit bind/listen steps (performed by systemd activation!)
UnixStreamServer.__init__(
self, server_address, handler_cls, bind_and_activate=False)
# Override socket
self.socket = socket.fromfd(
self.SYSTEMD_FIRST_SOCKET_FD, self.address_family, self.socket_type)
if __name__ == "__main__":
logging.basicConfig(level=logging.INFO)
HOST, PORT = "localhost", 9999 # not really needed here
CHECKPATH='/opt/foo/wouldbesysfsfile'
server = Server((HOST, PORT), Handler)
if not os.path.isfile(CHECKPATH):
logging.info("%s does not exist consume and reject message" % CHECKPATH)
server.handle_request()
logging.info("Handled, but going out of service now")
sys.exit(0);
server.serve_forever()
Create the service definition unit file at /etc/systemd/system/foo.service
(note that this unit refers to foo.socket
):
[Unit]
Description=Foo Service
After=network.target foo.socket
Requires=foo.socket
[Service]
Type=simple
ExecStart=/usr/bin/python /opt/foo/serve.py
TimeoutStopSec=5
[Install]
WantedBy=multi-user.target
Create the socket definition unit file at /etc/systemd/system/foo.socket
:
[Unit]
Description=Foo Socket
PartOf=foo.service
[Socket]
ListenStream=/run/foo.sock
[Install]
WantedBy=sockets.target
Send a message to the listening service:
echo "Hello World"| netcat -U /run/foo.sock
This is based on another gist It contains further Modifications:
- Let the service handle the initial message (to Nack it in the real case)
- Let the service then go "out of service" (like a one-shot)
- This allows to be restarted on further socket activity