Fix system installation state directory
The service was failing with 'Read-only file system' when trying to create discovered_sensors.json in the /etc/sensorpajen config directory. Changes: - config.py: Add STATE_DIR for runtime state - System mode: /var/lib/sensorpajen (writable at runtime) - Dev mode: config/ (same as config directory) - config.py: Use STATE_DIR for discovered_sensors.json path - debian/postinst: Create and own /var/lib/sensorpajen - debian/sensorpajen.service: Add /var/lib/sensorpajen to ReadWritePaths - debian/postinst: Remove discovered_sensors.json.example copy (created at runtime) This separates: - Config: /etc/sensorpajen (static, not updated by service) - State: /var/lib/sensorpajen (dynamic, updated by service at runtime)
This commit is contained in:
1
debian/files
vendored
1
debian/files
vendored
@@ -1,2 +1 @@
|
|||||||
sensorpajen_2.0.0-dev_all.deb misc optional
|
sensorpajen_2.0.0-dev_all.deb misc optional
|
||||||
sensorpajen_2.0.0-dev_amd64.buildinfo misc optional
|
|
||||||
|
|||||||
7
debian/postinst
vendored
7
debian/postinst
vendored
@@ -14,8 +14,13 @@ case "$1" in
|
|||||||
chown sensorpajen:sensorpajen /etc/sensorpajen
|
chown sensorpajen:sensorpajen /etc/sensorpajen
|
||||||
chmod 750 /etc/sensorpajen
|
chmod 750 /etc/sensorpajen
|
||||||
|
|
||||||
|
# Create state directory with proper permissions (writable at runtime)
|
||||||
|
mkdir -p /var/lib/sensorpajen
|
||||||
|
chown sensorpajen:sensorpajen /var/lib/sensorpajen
|
||||||
|
chmod 750 /var/lib/sensorpajen
|
||||||
|
|
||||||
# Copy example configs to /etc/sensorpajen if they don't exist
|
# Copy example configs to /etc/sensorpajen if they don't exist
|
||||||
for sample in sensorpajen.env.example sensors.json.example discovered_sensors.json.example; do
|
for sample in sensorpajen.env.example sensors.json.example; do
|
||||||
source_file="/usr/share/doc/sensorpajen/examples/$sample"
|
source_file="/usr/share/doc/sensorpajen/examples/$sample"
|
||||||
target_file="/etc/sensorpajen/${sample%.example}"
|
target_file="/etc/sensorpajen/${sample%.example}"
|
||||||
|
|
||||||
|
|||||||
2
debian/sensorpajen.service
vendored
2
debian/sensorpajen.service
vendored
@@ -26,7 +26,7 @@ SyslogIdentifier=sensorpajen
|
|||||||
PrivateTmp=true
|
PrivateTmp=true
|
||||||
ProtectSystem=strict
|
ProtectSystem=strict
|
||||||
ProtectHome=true
|
ProtectHome=true
|
||||||
ReadWritePaths=/etc/sensorpajen
|
ReadWritePaths=/etc/sensorpajen /var/lib/sensorpajen
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
||||||
|
|||||||
2
debian/sensorpajen/DEBIAN/control
vendored
2
debian/sensorpajen/DEBIAN/control
vendored
@@ -2,7 +2,7 @@ Package: sensorpajen
|
|||||||
Version: 2.0.0-dev
|
Version: 2.0.0-dev
|
||||||
Architecture: all
|
Architecture: all
|
||||||
Maintainer: Fredrik <fredrik@wahlberg.se>
|
Maintainer: Fredrik <fredrik@wahlberg.se>
|
||||||
Installed-Size: 110
|
Installed-Size: 111
|
||||||
Depends: python3 (>= 3.9), python3-venv, python3-pip, bluetooth, bluez, libcap2-bin
|
Depends: python3 (>= 3.9), python3-venv, python3-pip, bluetooth, bluez, libcap2-bin
|
||||||
Recommends: mosquitto-clients
|
Recommends: mosquitto-clients
|
||||||
Section: misc
|
Section: misc
|
||||||
|
|||||||
8
debian/sensorpajen/DEBIAN/md5sums
vendored
8
debian/sensorpajen/DEBIAN/md5sums
vendored
@@ -3,17 +3,17 @@
|
|||||||
940d73f24eb9f971ce27f9355e3072f3 opt/sensorpajen/scripts/approve-sensors.sh
|
940d73f24eb9f971ce27f9355e3072f3 opt/sensorpajen/scripts/approve-sensors.sh
|
||||||
20eb4f3839b990a530410768897402c0 opt/sensorpajen/src/sensorpajen/__init__.py
|
20eb4f3839b990a530410768897402c0 opt/sensorpajen/src/sensorpajen/__init__.py
|
||||||
1f452c46e42f8dc3751dba6ca68256e9 opt/sensorpajen/src/sensorpajen/approve_sensors.py
|
1f452c46e42f8dc3751dba6ca68256e9 opt/sensorpajen/src/sensorpajen/approve_sensors.py
|
||||||
da40d9df301d523d517d7cf2809d6f11 opt/sensorpajen/src/sensorpajen/config.py
|
8d781ed202be540358a970c2be50f54d opt/sensorpajen/src/sensorpajen/config.py
|
||||||
65c63383dde4f0b249b708f854ec75a3 opt/sensorpajen/src/sensorpajen/discovery_manager.py
|
65c63383dde4f0b249b708f854ec75a3 opt/sensorpajen/src/sensorpajen/discovery_manager.py
|
||||||
592f8a534833c9e403967fcc0ead8eb1 opt/sensorpajen/src/sensorpajen/main.py
|
7604c2bc0a854d6d43ff0f0646386fc5 opt/sensorpajen/src/sensorpajen/main.py
|
||||||
331bf9b314492acc6ce03896367f3cf6 opt/sensorpajen/src/sensorpajen/mqtt_publisher.py
|
331bf9b314492acc6ce03896367f3cf6 opt/sensorpajen/src/sensorpajen/mqtt_publisher.py
|
||||||
5f4ea191e35ce092f39ec0a4f663cb38 opt/sensorpajen/src/sensorpajen/sensor_reader.py
|
5f4ea191e35ce092f39ec0a4f663cb38 opt/sensorpajen/src/sensorpajen/sensor_reader.py
|
||||||
c8dd8fe8fc174a9cd35251fdf80e7b5f opt/sensorpajen/src/sensorpajen/utils.py
|
c8dd8fe8fc174a9cd35251fdf80e7b5f opt/sensorpajen/src/sensorpajen/utils.py
|
||||||
c9c22f9c1d65bfafd89fa45f16b7192b usr/lib/systemd/system/sensorpajen.service
|
b9ad3ea8307d8ed8e938da37ad00f229 usr/lib/systemd/system/sensorpajen.service
|
||||||
4ddb9618c940286f91df901ec818959a usr/share/doc/sensorpajen/INSTALL.md.gz
|
4ddb9618c940286f91df901ec818959a usr/share/doc/sensorpajen/INSTALL.md.gz
|
||||||
bd2f1371c60af415bc9d0dbc1111184d usr/share/doc/sensorpajen/ROADMAP.md.gz
|
bd2f1371c60af415bc9d0dbc1111184d usr/share/doc/sensorpajen/ROADMAP.md.gz
|
||||||
380e8e6b01b757ceac05bc5805844ae4 usr/share/doc/sensorpajen/changelog.Debian.gz
|
380e8e6b01b757ceac05bc5805844ae4 usr/share/doc/sensorpajen/changelog.Debian.gz
|
||||||
14152a98d7cd7fe8daf280aacc4cbf3f usr/share/doc/sensorpajen/examples/discovered_sensors.json.example
|
14152a98d7cd7fe8daf280aacc4cbf3f usr/share/doc/sensorpajen/examples/discovered_sensors.json.example
|
||||||
387cb9ee7f22570312604e2cc07ca7a0 usr/share/doc/sensorpajen/examples/sensorpajen.env.example
|
74c99b732363f93f0a1c134e1a8c3d35 usr/share/doc/sensorpajen/examples/sensorpajen.env.example
|
||||||
292efbddd951c39cb2c9546d5fac5e05 usr/share/doc/sensorpajen/examples/sensors.json.example
|
292efbddd951c39cb2c9546d5fac5e05 usr/share/doc/sensorpajen/examples/sensors.json.example
|
||||||
5f647c63bfc3b174611694779fd215e0 usr/share/doc/sensorpajen/readme.md.gz
|
5f647c63bfc3b174611694779fd215e0 usr/share/doc/sensorpajen/readme.md.gz
|
||||||
|
|||||||
18
debian/sensorpajen/DEBIAN/postinst
vendored
18
debian/sensorpajen/DEBIAN/postinst
vendored
@@ -14,8 +14,13 @@ case "$1" in
|
|||||||
chown sensorpajen:sensorpajen /etc/sensorpajen
|
chown sensorpajen:sensorpajen /etc/sensorpajen
|
||||||
chmod 750 /etc/sensorpajen
|
chmod 750 /etc/sensorpajen
|
||||||
|
|
||||||
|
# Create state directory with proper permissions (writable at runtime)
|
||||||
|
mkdir -p /var/lib/sensorpajen
|
||||||
|
chown sensorpajen:sensorpajen /var/lib/sensorpajen
|
||||||
|
chmod 750 /var/lib/sensorpajen
|
||||||
|
|
||||||
# Copy example configs to /etc/sensorpajen if they don't exist
|
# Copy example configs to /etc/sensorpajen if they don't exist
|
||||||
for sample in sensorpajen.env.example sensors.json.example discovered_sensors.json.example; do
|
for sample in sensorpajen.env.example sensors.json.example; do
|
||||||
source_file="/usr/share/doc/sensorpajen/examples/$sample"
|
source_file="/usr/share/doc/sensorpajen/examples/$sample"
|
||||||
target_file="/etc/sensorpajen/${sample%.example}"
|
target_file="/etc/sensorpajen/${sample%.example}"
|
||||||
|
|
||||||
@@ -48,7 +53,7 @@ case "$1" in
|
|||||||
venv/bin/pip install -r /opt/sensorpajen/requirements.txt
|
venv/bin/pip install -r /opt/sensorpajen/requirements.txt
|
||||||
else
|
else
|
||||||
echo "Warning: requirements.txt not found, installing bluepy and paho-mqtt directly"
|
echo "Warning: requirements.txt not found, installing bluepy and paho-mqtt directly"
|
||||||
venv/bin/pip install bluepy paho-mqtt
|
venv/bin/pip install bluepy paho-mqtt pybluez
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
@@ -56,6 +61,15 @@ case "$1" in
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Install sensorpajen package itself
|
||||||
|
echo "Installing sensorpajen application..."
|
||||||
|
cd /opt/sensorpajen
|
||||||
|
venv/bin/pip install --no-deps . || {
|
||||||
|
echo "Error: Failed to install sensorpajen package"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
cd /
|
||||||
|
|
||||||
# Set ownership of application directory BEFORE setting capabilities
|
# Set ownership of application directory BEFORE setting capabilities
|
||||||
chown -R sensorpajen:sensorpajen /opt/sensorpajen
|
chown -R sensorpajen:sensorpajen /opt/sensorpajen
|
||||||
|
|
||||||
|
|||||||
@@ -19,10 +19,12 @@ if Path('/opt/sensorpajen').exists():
|
|||||||
# System installation
|
# System installation
|
||||||
PROJECT_ROOT = Path('/opt/sensorpajen')
|
PROJECT_ROOT = Path('/opt/sensorpajen')
|
||||||
CONFIG_DIR = Path('/etc/sensorpajen')
|
CONFIG_DIR = Path('/etc/sensorpajen')
|
||||||
|
STATE_DIR = Path('/var/lib/sensorpajen')
|
||||||
else:
|
else:
|
||||||
# Development installation (3 levels up from this file: src/sensorpajen/config.py)
|
# Development installation (3 levels up from this file: src/sensorpajen/config.py)
|
||||||
PROJECT_ROOT = Path(__file__).parent.parent.parent
|
PROJECT_ROOT = Path(__file__).parent.parent.parent
|
||||||
CONFIG_DIR = PROJECT_ROOT / "config"
|
CONFIG_DIR = PROJECT_ROOT / "config"
|
||||||
|
STATE_DIR = CONFIG_DIR
|
||||||
|
|
||||||
# MQTT Configuration from environment
|
# MQTT Configuration from environment
|
||||||
MQTT_HOST = os.environ.get("MQTT_HOST")
|
MQTT_HOST = os.environ.get("MQTT_HOST")
|
||||||
@@ -63,7 +65,7 @@ NTFY_TOKEN = os.environ.get("NTFY_TOKEN", "")
|
|||||||
# Discovery settings
|
# Discovery settings
|
||||||
DISCOVERED_SENSORS_FILE = os.environ.get(
|
DISCOVERED_SENSORS_FILE = os.environ.get(
|
||||||
"DISCOVERED_SENSORS_FILE",
|
"DISCOVERED_SENSORS_FILE",
|
||||||
str(CONFIG_DIR / "discovered_sensors.json")
|
str(STATE_DIR / "discovered_sensors.json")
|
||||||
)
|
)
|
||||||
CONFIG_RELOAD_INTERVAL = int(os.environ.get("CONFIG_RELOAD_INTERVAL", "900")) # 15 minutes
|
CONFIG_RELOAD_INTERVAL = int(os.environ.get("CONFIG_RELOAD_INTERVAL", "900")) # 15 minutes
|
||||||
|
|
||||||
@@ -85,11 +87,11 @@ class SensorConfig:
|
|||||||
def load(self):
|
def load(self):
|
||||||
"""Load sensor configuration from JSON file."""
|
"""Load sensor configuration from JSON file."""
|
||||||
if not self.config_file.exists():
|
if not self.config_file.exists():
|
||||||
raise FileNotFoundError(
|
logger.warning(
|
||||||
f"Sensor configuration file not found: {self.config_file}\n"
|
f"Sensor configuration file not found: {self.config_file}\n"
|
||||||
f"Please copy config/sensors.json.example to config/sensors.json "
|
f"Starting with no sensors - use discovery to add sensors"
|
||||||
f"and configure your sensors."
|
|
||||||
)
|
)
|
||||||
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with open(self.config_file, 'r') as f:
|
with open(self.config_file, 'r') as f:
|
||||||
|
|||||||
@@ -125,9 +125,9 @@ class Sensorpajen:
|
|||||||
self.sensor_config = config.SensorConfig()
|
self.sensor_config = config.SensorConfig()
|
||||||
|
|
||||||
if len(self.sensor_config.sensors) == 0:
|
if len(self.sensor_config.sensors) == 0:
|
||||||
self.logger.error("No sensors configured!")
|
self.logger.warning("No sensors configured")
|
||||||
self.logger.error("Please configure sensors in config/sensors.json")
|
self.logger.warning("Starting in discovery-only mode")
|
||||||
sys.exit(1)
|
self.logger.warning("Use 'sensorpajen approve-sensors' to add sensors")
|
||||||
|
|
||||||
# Initialize discovery manager
|
# Initialize discovery manager
|
||||||
self.logger.info("Initializing discovery manager...")
|
self.logger.info("Initializing discovery manager...")
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ SyslogIdentifier=sensorpajen
|
|||||||
PrivateTmp=true
|
PrivateTmp=true
|
||||||
ProtectSystem=strict
|
ProtectSystem=strict
|
||||||
ProtectHome=true
|
ProtectHome=true
|
||||||
ReadWritePaths=/etc/sensorpajen
|
ReadWritePaths=/etc/sensorpajen /var/lib/sensorpajen
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
||||||
|
|||||||
@@ -5,9 +5,16 @@ MQTT_USER=hasse
|
|||||||
MQTT_PASSWORD=casablanca
|
MQTT_PASSWORD=casablanca
|
||||||
MQTT_CLIENT_ID=mibridge
|
MQTT_CLIENT_ID=mibridge
|
||||||
|
|
||||||
# Sensor Configuration (relative to project root)
|
# Sensor Configuration
|
||||||
SENSOR_CONFIG_FILE=config/sensors.json
|
# For system installation (/opt/sensorpajen): Use absolute paths
|
||||||
DISCOVERED_SENSORS_FILE=config/discovered_sensors.json
|
# SENSOR_CONFIG_FILE=/etc/sensorpajen/sensors.json
|
||||||
|
# DISCOVERED_SENSORS_FILE=/etc/sensorpajen/discovered_sensors.json
|
||||||
|
#
|
||||||
|
# For development installation: Use relative paths (from project root)
|
||||||
|
# SENSOR_CONFIG_FILE=config/sensors.json
|
||||||
|
# DISCOVERED_SENSORS_FILE=config/discovered_sensors.json
|
||||||
|
#
|
||||||
|
# If not set, defaults will be used based on installation type
|
||||||
|
|
||||||
# Application Settings
|
# Application Settings
|
||||||
WATCHDOG_TIMEOUT=5
|
WATCHDOG_TIMEOUT=5
|
||||||
|
|||||||
@@ -19,10 +19,12 @@ if Path('/opt/sensorpajen').exists():
|
|||||||
# System installation
|
# System installation
|
||||||
PROJECT_ROOT = Path('/opt/sensorpajen')
|
PROJECT_ROOT = Path('/opt/sensorpajen')
|
||||||
CONFIG_DIR = Path('/etc/sensorpajen')
|
CONFIG_DIR = Path('/etc/sensorpajen')
|
||||||
|
STATE_DIR = Path('/var/lib/sensorpajen')
|
||||||
else:
|
else:
|
||||||
# Development installation (3 levels up from this file: src/sensorpajen/config.py)
|
# Development installation (3 levels up from this file: src/sensorpajen/config.py)
|
||||||
PROJECT_ROOT = Path(__file__).parent.parent.parent
|
PROJECT_ROOT = Path(__file__).parent.parent.parent
|
||||||
CONFIG_DIR = PROJECT_ROOT / "config"
|
CONFIG_DIR = PROJECT_ROOT / "config"
|
||||||
|
STATE_DIR = CONFIG_DIR
|
||||||
|
|
||||||
# MQTT Configuration from environment
|
# MQTT Configuration from environment
|
||||||
MQTT_HOST = os.environ.get("MQTT_HOST")
|
MQTT_HOST = os.environ.get("MQTT_HOST")
|
||||||
@@ -63,7 +65,7 @@ NTFY_TOKEN = os.environ.get("NTFY_TOKEN", "")
|
|||||||
# Discovery settings
|
# Discovery settings
|
||||||
DISCOVERED_SENSORS_FILE = os.environ.get(
|
DISCOVERED_SENSORS_FILE = os.environ.get(
|
||||||
"DISCOVERED_SENSORS_FILE",
|
"DISCOVERED_SENSORS_FILE",
|
||||||
str(CONFIG_DIR / "discovered_sensors.json")
|
str(STATE_DIR / "discovered_sensors.json")
|
||||||
)
|
)
|
||||||
CONFIG_RELOAD_INTERVAL = int(os.environ.get("CONFIG_RELOAD_INTERVAL", "900")) # 15 minutes
|
CONFIG_RELOAD_INTERVAL = int(os.environ.get("CONFIG_RELOAD_INTERVAL", "900")) # 15 minutes
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user