particle-os-tools/src/apt-ostree.py/install.sh
Joe Particle 8c470a56b5 feat: Implement production-ready systemd service best practices
- Update systemd service file with Type=simple and comprehensive locking
- Enhance D-Bus service and policy files for proper activation
- Remove OSTree dependency for test mode compatibility
- Implement automated service file installation and cleanup
- Add comprehensive systemd usage documentation
- Update changelog and TODO to reflect completed systemd improvements
- Service now successfully running under systemd management

This completes the systemd service integration with production-ready
configuration and best practices for daemon lifecycle management.
2025-07-16 16:13:35 +00:00

315 lines
No EOL
9.5 KiB
Bash
Executable file

#!/bin/bash
# apt-ostree Installation Script
# Installs apt-ostree with 1:1 rpm-ostree compatibility
set -e
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Configuration
INSTALL_DIR="/usr/local/bin"
SERVICE_DIR="/etc/systemd/system"
CONFIG_DIR="/etc/apt-ostree"
LOG_DIR="/var/log"
DATA_DIR="/var/lib/apt-ostree"
echo -e "${BLUE}apt-ostree Installation Script${NC}"
echo "Installing apt-ostree with 1:1 rpm-ostree compatibility"
echo ""
# Check if running as root
if [[ $EUID -ne 0 ]]; then
echo -e "${RED}Error: This script must be run as root${NC}"
exit 1
fi
# Check Python version
PYTHON_VERSION=$(python3 --version 2>&1 | cut -d' ' -f2 | cut -d'.' -f1,2)
# Fix: allow 3.8 and higher
if [[ $(printf '%s\n' "3.8" "$PYTHON_VERSION" | sort -V | head -n1) != "3.8" ]]; then
echo -e "${RED}Error: Python 3.8 or higher is required (found $PYTHON_VERSION)${NC}"
exit 1
fi
echo -e "${GREEN}✓ Python version check passed${NC}"
# Install Python dependencies
echo -e "${BLUE}Installing Python dependencies...${NC}"
cd "$(dirname "$0")/python"
if ! pip3 install --break-system-packages -r requirements.txt; then
echo -e "${RED}Error: Failed to install Python dependencies${NC}"
exit 1
fi
echo -e "${GREEN}✓ Python dependencies installed${NC}"
# Create directories
echo -e "${BLUE}Creating directories...${NC}"
mkdir -p "$CONFIG_DIR"
mkdir -p "$LOG_DIR"
mkdir -p "$DATA_DIR"
mkdir -p "$INSTALL_DIR"
mkdir -p "/var/cache/apt-ostree"
mkdir -p "/var/log/apt-ostree"
echo -e "${GREEN}✓ Directories created${NC}"
# Install apt-ostree binary
echo -e "${BLUE}Installing apt-ostree binary...${NC}"
cat > "$INSTALL_DIR/apt-ostree" << 'EOF'
#!/usr/bin/env python3
"""
apt-ostree - Hybrid image/package system for Debian/Ubuntu
1:1 compatibility with rpm-ostree
"""
import sys
import os
# Add the apt-ostree Python module to the path
sys.path.insert(0, '/usr/local/lib/apt-ostree')
from main import main
if __name__ == '__main__':
sys.exit(main())
EOF
chmod +x "$INSTALL_DIR/apt-ostree"
# Install Python modules
echo -e "${BLUE}Installing Python modules...${NC}"
PYTHON_LIB_DIR="/usr/local/lib/apt-ostree"
mkdir -p "$PYTHON_LIB_DIR"
cp apt_ostree.py "$PYTHON_LIB_DIR/"
cp apt_ostree_cli.py "$PYTHON_LIB_DIR/"
cp main.py "$PYTHON_LIB_DIR/"
# Create __init__.py
touch "$PYTHON_LIB_DIR/__init__.py"
echo -e "${GREEN}✓ Python modules installed${NC}"
# Install systemd service file
echo -e "${BLUE}Installing systemd service file...${NC}"
SCRIPT_DIR="$(dirname "$0")"
if [[ -f "$SCRIPT_DIR/apt-ostreed.service" ]]; then
cp "$SCRIPT_DIR/apt-ostreed.service" "$SERVICE_DIR/"
chmod 644 "$SERVICE_DIR/apt-ostreed.service"
echo -e "${GREEN}✓ Systemd service file installed${NC}"
else
echo -e "${YELLOW}Warning: apt-ostreed.service not found, creating default...${NC}"
cat > "$SERVICE_DIR/apt-ostreed.service" << EOF
[Unit]
Description=apt-ostree System Management Daemon
Documentation=man:apt-ostree(1)
ConditionPathExists=/ostree
RequiresMountsFor=/boot
After=dbus.service
[Service]
Type=simple
User=root
Group=root
# Lock file to prevent multiple instances
PIDFile=/var/run/apt-ostreed.pid
RuntimeDirectory=apt-ostreed
RuntimeDirectoryMode=0755
# Prevent multiple instances
ExecStartPre=/bin/rm -f /var/run/apt-ostreed.pid
ExecStartPre=/bin/rm -f /run/apt-ostreed/daemon.lock
ExecStartPre=/bin/mkdir -p /run/apt-ostreed
ExecStartPre=/bin/touch /run/apt-ostreed/daemon.lock
# Main daemon execution
ExecStart=/usr/bin/python3 /usr/local/lib/apt-ostree/apt_ostree.py --daemon --pid-file=/var/run/apt-ostreed.pid
# Cleanup on stop
ExecStopPost=/bin/rm -f /var/run/apt-ostreed.pid
ExecStopPost=/bin/rm -f /run/apt-ostreed/daemon.lock
ExecReload=/bin/kill -HUP \$MAINPID
Restart=on-failure
RestartSec=5
TimeoutStartSec=5m
TimeoutStopSec=30s
StandardOutput=journal
StandardError=journal
SyslogIdentifier=apt-ostreed
# Security settings
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
RestrictRealtime=true
RestrictSUIDSGID=true
PrivateTmp=true
PrivateDevices=true
PrivateNetwork=false
ReadWritePaths=/var/lib/apt-ostree /var/cache/apt-ostree /var/log/apt-ostree /ostree /boot /var/run /run
# OSTree and APT specific paths
ReadWritePaths=/var/lib/apt /var/cache/apt /var/lib/dpkg /var/lib/ostree
# Environment variables
Environment="PYTHONPATH=/usr/local/lib/apt-ostree"
Environment="DOWNLOAD_FILELISTS=false"
Environment="GIO_USE_VFS=local"
[Install]
WantedBy=multi-user.target
EOF
echo -e "${GREEN}✓ Default systemd service created${NC}"
fi
# Create configuration file
echo -e "${BLUE}Creating configuration...${NC}"
cat > "$CONFIG_DIR/config.json" << EOF
{
"daemon": {
"enabled": true,
"log_level": "INFO",
"workspace": "$DATA_DIR"
},
"compatibility": {
"rpm_ostree": true,
"output_format": "rpm_ostree"
},
"security": {
"require_root": true,
"polkit_integration": true
}
}
EOF
echo -e "${GREEN}✓ Configuration created${NC}"
# Set permissions
echo -e "${BLUE}Setting permissions...${NC}"
chown -R root:root "$CONFIG_DIR"
chmod 755 "$CONFIG_DIR"
chmod 644 "$CONFIG_DIR/config.json"
chown -R root:root "$DATA_DIR"
chmod 755 "$DATA_DIR"
chown -R root:root "/var/cache/apt-ostree"
chmod 755 "/var/cache/apt-ostree"
chown -R root:root "/var/log/apt-ostree"
chmod 755 "/var/log/apt-ostree"
chown root:root "$LOG_DIR/apt-ostree.log" 2>/dev/null || true
chmod 644 "$LOG_DIR/apt-ostree.log" 2>/dev/null || true
echo -e "${GREEN}✓ Permissions set${NC}"
# Reload systemd
echo -e "${BLUE}Reloading systemd...${NC}"
systemctl daemon-reload
echo -e "${GREEN}✓ Systemd reloaded${NC}"
# Install D-Bus policy file
echo -e "${BLUE}Installing D-Bus policy file...${NC}"
DBUS_POLICY_SRC="$(dirname "$0")/dbus-policy/org.debian.aptostree1.conf"
DBUS_POLICY_DEST="/etc/dbus-1/system.d/org.debian.aptostree1.conf"
if [[ -f "$DBUS_POLICY_SRC" ]]; then
cp "$DBUS_POLICY_SRC" "$DBUS_POLICY_DEST"
chmod 644 "$DBUS_POLICY_DEST"
echo -e "${GREEN}\u2713 D-Bus policy file installed${NC}"
echo -e "${BLUE}Reloading D-Bus...${NC}"
systemctl reload dbus || echo -e "${YELLOW}Warning: Could not reload dbus. You may need to reboot or reload manually.${NC}"
else
echo -e "${YELLOW}Warning: D-Bus policy file not found at $DBUS_POLICY_SRC. D-Bus integration may not work!${NC}"
fi
# Install D-Bus activation service file
echo -e "${BLUE}Installing D-Bus activation service file...${NC}"
DBUS_SERVICE_DIR="/usr/share/dbus-1/system-services"
mkdir -p "$DBUS_SERVICE_DIR"
if [[ -f "$SCRIPT_DIR/org.debian.aptostree1.service" ]]; then
cp "$SCRIPT_DIR/org.debian.aptostree1.service" "$DBUS_SERVICE_DIR/"
chmod 644 "$DBUS_SERVICE_DIR/org.debian.aptostree1.service"
echo -e "${GREEN}✓ D-Bus activation service file installed${NC}"
else
echo -e "${YELLOW}Warning: org.debian.aptostree1.service not found, creating default...${NC}"
cat > "$DBUS_SERVICE_DIR/org.debian.aptostree1.service" << EOF
[D-BUS Service]
Name=org.debian.aptostree1
Exec=/usr/bin/python3 /usr/local/lib/apt-ostree/apt_ostree.py
User=root
SystemdService=apt-ostreed.service
EOF
chmod 644 "$DBUS_SERVICE_DIR/org.debian.aptostree1.service"
echo -e "${GREEN}✓ Default D-Bus activation service file created${NC}"
fi
# Test installation
echo -e "${BLUE}Testing installation...${NC}"
if "$INSTALL_DIR/apt-ostree" --help >/dev/null 2>&1; then
echo -e "${GREEN}✓ apt-ostree command works${NC}"
else
echo -e "${RED}✗ apt-ostree command failed${NC}"
exit 1
fi
# Enable and start service (optional)
read -p "Do you want to enable and start the apt-ostree daemon? (y/N): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
echo -e "${BLUE}Enabling and starting apt-ostree daemon...${NC}"
systemctl enable apt-ostreed.service
systemctl start apt-ostreed.service
if systemctl is-active --quiet apt-ostreed.service; then
echo -e "${GREEN}✓ apt-ostree daemon is running${NC}"
else
echo -e "${YELLOW}⚠ apt-ostree daemon failed to start${NC}"
echo "Check logs with: journalctl -u apt-ostreed.service"
fi
fi
echo ""
echo -e "${GREEN}🎉 apt-ostree installation completed!${NC}"
echo ""
echo -e "${BLUE}Usage examples:${NC}"
echo " apt-ostree status # Show system status"
echo " apt-ostree upgrade --reboot # Upgrade and reboot"
echo " apt-ostree install firefox --reboot # Install package and reboot"
echo " apt-ostree rollback # Rollback to previous deployment"
echo " apt-ostree kargs add console=ttyS0 # Add kernel argument"
echo ""
echo -e "${BLUE}Service management:${NC}"
echo " systemctl status apt-ostreed # Check daemon status"
echo " systemctl start apt-ostreed # Start daemon"
echo " systemctl stop apt-ostreed # Stop daemon"
echo " journalctl -u apt-ostreed -f # View daemon logs"
echo ""
echo -e "${BLUE}Files installed:${NC}"
echo " Binary: $INSTALL_DIR/apt-ostree"
echo " Service: $SERVICE_DIR/apt-ostreed.service"
echo " Config: $CONFIG_DIR/config.json"
echo " Data: $DATA_DIR"
echo " Logs: $LOG_DIR/apt-ostree.log"
echo " D-Bus Service: /usr/share/dbus-1/system-services/org.debian.aptostree1.service"
echo " D-Bus Policy: /etc/dbus-1/system.d/org.debian.aptostree1.conf"
echo ""
echo -e "${GREEN}apt-ostree provides 1:1 compatibility with rpm-ostree commands!${NC}"
echo ""
echo -e "${BLUE}To test D-Bus connection:${NC}"
echo " sudo dbus-send --system --dest=org.debian.aptostree1 \\"
echo " /org/debian/aptostree1/Sysroot \\"
echo " org.freedesktop.DBus.Introspectable.Introspect"