Systemd Services¶
fscm provides utilities for creating and managing systemd services.
Installation¶
The systemd module is included with fscm:
Creating Simple Services¶
The simple_service() function creates a complete systemd service:
from fscm.modules import systemd
# Create a service that runs a command
systemd.simple_service(
name="myapp",
exec_start="/usr/bin/python3 /opt/myapp/app.py",
description="My Application",
user="www-data",
working_dir="/opt/myapp"
)
This creates:
- /etc/systemd/system/myapp.service — Service unit file
- Enables the service to start on boot
- Starts the service
Parameters¶
| Parameter | Type | Description |
|---|---|---|
name |
str | Service name |
exec_start |
str | Command to run |
description |
str | Service description |
user |
str | User to run as |
group |
str | Group to run as |
working_dir |
str | Working directory |
env_file |
str | Environment file path |
env_vars |
dict | Environment variables |
restart |
str | Restart policy (always, on-failure) |
restart_sec |
int | Seconds before restart |
after |
list | Services to start after |
wants |
list | Soft dependencies |
requires |
list | Hard dependencies |
Service with Environment Variables¶
from fscm.modules import systemd
systemd.simple_service(
name="myapp",
exec_start="/opt/myapp/venv/bin/python app.py",
user="myapp",
working_dir="/opt/myapp",
env_vars={
"DATABASE_URL": "postgresql://localhost/myapp",
"REDIS_URL": "redis://localhost:6379",
"DEBUG": "false"
}
)
Service with Environment File¶
import fscm
from fscm.modules import systemd
# Create environment file
fscm.file(
"/etc/myapp/env",
"""
DATABASE_URL=postgresql://localhost/myapp
REDIS_URL=redis://localhost:6379
SECRET_KEY=your-secret-key
""",
mode="0600",
owner="myapp:myapp"
)
# Create service using env file
systemd.simple_service(
name="myapp",
exec_start="/opt/myapp/venv/bin/gunicorn app:app",
user="myapp",
working_dir="/opt/myapp",
env_file="/etc/myapp/env"
)
User Services¶
Create services that run under a user's systemd instance:
from fscm.modules import systemd
systemd.user_simple_service(
name="myapp",
exec_start="/home/user/myapp/run.sh",
description="My User Application",
user="myuser"
)
This creates the service in ~/.config/systemd/user/ and manages it with systemctl --user.
Docker Compose Services¶
Run docker-compose projects as systemd services:
from fscm.modules import systemd
systemd.docker_compose_service(
name="mystack",
compose_file="/opt/mystack/docker-compose.yml",
description="My Docker Stack"
)
This creates a service that:
- Runs docker-compose up on start
- Runs docker-compose down on stop
- Depends on docker.service
Parameters¶
| Parameter | Type | Description |
|---|---|---|
name |
str | Service name |
compose_file |
str | Path to docker-compose.yml |
description |
str | Service description |
project_name |
str | Docker Compose project name |
env_file |
str | Environment file for compose |
Managing Services Manually¶
For more control, create unit files directly:
import fscm
unit_content = """
[Unit]
Description=My Custom Service
After=network.target postgresql.service
Requires=postgresql.service
[Service]
Type=notify
User=myapp
Group=myapp
WorkingDirectory=/opt/myapp
ExecStart=/opt/myapp/venv/bin/gunicorn --workers 4 app:app
ExecReload=/bin/kill -s HUP $MAINPID
Restart=always
RestartSec=5
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
"""
fscm.file("/etc/systemd/system/myapp.service", unit_content, mode="0644")
fscm.run("systemctl daemon-reload", sudo=True)
fscm.run("systemctl enable myapp", sudo=True)
fscm.run("systemctl start myapp", sudo=True)
Service Control¶
import fscm
# Reload systemd after changes
fscm.run("systemctl daemon-reload", sudo=True)
# Enable service (start on boot)
fscm.run("systemctl enable myapp", sudo=True)
# Start service
fscm.run("systemctl start myapp", sudo=True)
# Stop service
fscm.run("systemctl stop myapp", sudo=True)
# Restart service
fscm.run("systemctl restart myapp", sudo=True)
# Check status
result = fscm.run_ro("systemctl is-active myapp")
if result.ok:
print("Service is running")
Example: Gunicorn Service¶
import fscm
from fscm.modules import systemd
def setup_gunicorn_service(
app_name: str,
app_dir: str,
app_module: str,
workers: int = 4,
user: str = "www-data"
):
"""Set up a Gunicorn WSGI service."""
venv = f"{app_dir}/venv"
# Create the service
systemd.simple_service(
name=app_name,
exec_start=(
f"{venv}/bin/gunicorn "
f"--workers {workers} "
f"--bind unix:/run/{app_name}.sock "
f"{app_module}"
),
description=f"{app_name} Gunicorn Service",
user=user,
group=user,
working_dir=app_dir,
env_file=f"/etc/{app_name}/env",
restart="always",
restart_sec=5
)
# Usage
setup_gunicorn_service(
app_name="myapp",
app_dir="/opt/myapp",
app_module="myapp.wsgi:application",
workers=4
)
Example: Timer Service¶
Create a service that runs on a schedule:
import fscm
# Service that does the actual work
service = """
[Unit]
Description=Backup Service
[Service]
Type=oneshot
ExecStart=/opt/scripts/backup.sh
User=backup
"""
# Timer that triggers the service
timer = """
[Unit]
Description=Run backup daily
[Timer]
OnCalendar=daily
Persistent=true
[Install]
WantedBy=timers.target
"""
fscm.file("/etc/systemd/system/backup.service", service, mode="0644")
fscm.file("/etc/systemd/system/backup.timer", timer, mode="0644")
fscm.run("systemctl daemon-reload", sudo=True)
fscm.run("systemctl enable backup.timer", sudo=True)
fscm.run("systemctl start backup.timer", sudo=True)
Example: Socket-Activated Service¶
import fscm
# Socket unit
socket = """
[Unit]
Description=My App Socket
[Socket]
ListenStream=/run/myapp.sock
SocketUser=www-data
SocketGroup=www-data
SocketMode=0660
[Install]
WantedBy=sockets.target
"""
# Service unit
service = """
[Unit]
Description=My App Service
Requires=myapp.socket
[Service]
Type=notify
User=myapp
ExecStart=/opt/myapp/venv/bin/gunicorn --workers 4 -b unix:/run/myapp.sock app:app
Restart=always
"""
fscm.file("/etc/systemd/system/myapp.socket", socket, mode="0644")
fscm.file("/etc/systemd/system/myapp.service", service, mode="0644")
fscm.run("systemctl daemon-reload", sudo=True)
fscm.run("systemctl enable myapp.socket", sudo=True)
fscm.run("systemctl start myapp.socket", sudo=True)
Next Steps¶
- Docker Module — Container management
- Examples — Complete service examples