Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save drmalex07/333d8a88c4918954e8e4 to your computer and use it in GitHub Desktop.
Save drmalex07/333d8a88c4918954e8e4 to your computer and use it in GitHub Desktop.
An example network service with systemd-activated socket in Python. #systemd #python #socket #socket-activation

README

The example below creates a TCP 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.

An example server

Create an simple echo server at /opt/foo/serve.py.

#!/usr/bin/python

from SocketServer import TCPServer, StreamRequestHandler
import socket
import logging

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(TCPServer):
    
    # 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!)
        TCPServer.__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
    server = Server((HOST, PORT), Handler)
    server.serve_forever()

Define the systemd service unit

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

Define the systemd socket unit

Create the socket definition unit file at /etc/systemd/system/foo.socket:

[Unit]
Description=Foo Socket
PartOf=foo.service

[Socket]
ListenStream=127.0.0.1:9999

[Install]
WantedBy=sockets.target

Test it

Send a message to the listening service:

echo "Hello World"| netcat 127.0.0.1 9999
@pkaramol
Copy link

This is very useful thanks for sharing.

Are there any throttling limits on this imposed say by python or something?

If I open it up (by changing 127.0.0.1 --> 0.0.0.0) and have a syslog-ng server streaming on this listener, could there (in theory) be any logs lost due to the rate that syslog-ng serves data?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment