mirror of
https://github.com/LibreQoE/LibreQoS.git
synced 2025-02-25 18:55:32 -06:00
Add safegaurd against running LibreQoS.py more than once at a time.
ISSUE #52 * Added file locking commands to the Python/Rust library. * When LibreQoS.py starts, it checks that /var/run/libreqos.lock does not exist. If it does, it checks that it contains a PID and that PID is not still running with a python process. * If the lock file exists and is valid, execution aborts. * If the lock file exists and is invalid, it is cleaned. * Cleans the lock on termination.
This commit is contained in:
@@ -23,7 +23,8 @@ from ispConfig import sqm, upstreamBandwidthCapacityDownloadMbps, upstreamBandwi
|
|||||||
runShellCommandsAsSudo, generatedPNDownloadMbps, generatedPNUploadMbps, queuesAvailableOverride, \
|
runShellCommandsAsSudo, generatedPNDownloadMbps, generatedPNUploadMbps, queuesAvailableOverride, \
|
||||||
OnAStick
|
OnAStick
|
||||||
|
|
||||||
from liblqos_python import is_lqosd_alive, clear_ip_mappings, delete_ip_mapping, validate_shaped_devices
|
from liblqos_python import is_lqosd_alive, clear_ip_mappings, delete_ip_mapping, validate_shaped_devices, \
|
||||||
|
is_libre_already_running, create_lock_file, free_lock_file
|
||||||
|
|
||||||
# Automatically account for TCP overhead of plans. For example a 100Mbps plan needs to be set to 109Mbps for the user to ever see that result on a speed test
|
# Automatically account for TCP overhead of plans. For example a 100Mbps plan needs to be set to 109Mbps for the user to ever see that result on a speed test
|
||||||
# Does not apply to nodes of any sort, just endpoint devices
|
# Does not apply to nodes of any sort, just endpoint devices
|
||||||
@@ -1260,12 +1261,21 @@ def refreshShapersUpdateOnly():
|
|||||||
print("refreshShapersUpdateOnly completed on " + datetime.now().strftime("%d/%m/%Y %H:%M:%S"))
|
print("refreshShapersUpdateOnly completed on " + datetime.now().strftime("%d/%m/%Y %H:%M:%S"))
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
# Check that the host lqosd is running
|
||||||
if is_lqosd_alive():
|
if is_lqosd_alive():
|
||||||
print("lqosd is running")
|
print("lqosd is running")
|
||||||
else:
|
else:
|
||||||
print("ERROR: lqosd is not running. Aborting")
|
print("ERROR: lqosd is not running. Aborting")
|
||||||
os._exit(-1)
|
os._exit(-1)
|
||||||
|
|
||||||
|
# Check that we aren't running LibreQoS.py more than once at a time
|
||||||
|
if is_libre_already_running():
|
||||||
|
print("LibreQoS.py is already running in another process. Aborting.")
|
||||||
|
os._exit(-1)
|
||||||
|
|
||||||
|
# We've got this far, so create a lock file
|
||||||
|
create_lock_file()
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'-d', '--debug',
|
'-d', '--debug',
|
||||||
@@ -1305,3 +1315,6 @@ if __name__ == '__main__':
|
|||||||
else:
|
else:
|
||||||
# Refresh and/or set up queues
|
# Refresh and/or set up queues
|
||||||
refreshShapers()
|
refreshShapers()
|
||||||
|
|
||||||
|
# Free the lock file
|
||||||
|
free_lock_file()
|
||||||
2
src/rust/Cargo.lock
generated
2
src/rust/Cargo.lock
generated
@@ -1362,7 +1362,9 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"lqos_bus",
|
"lqos_bus",
|
||||||
|
"nix",
|
||||||
"pyo3",
|
"pyo3",
|
||||||
|
"sysinfo",
|
||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -12,3 +12,5 @@ pyo3 = "0.17"
|
|||||||
lqos_bus = { path = "../lqos_bus" }
|
lqos_bus = { path = "../lqos_bus" }
|
||||||
tokio = { version = "1.22", features = [ "rt", "macros", "net", "io-util", "time" ] }
|
tokio = { version = "1.22", features = [ "rt", "macros", "net", "io-util", "time" ] }
|
||||||
anyhow = "1"
|
anyhow = "1"
|
||||||
|
sysinfo = "0"
|
||||||
|
nix = "0"
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
|
use std::{path::Path, fs::{File, remove_file}, io::Write};
|
||||||
use lqos_bus::{BusRequest, BusResponse, TcHandle};
|
use lqos_bus::{BusRequest, BusResponse, TcHandle};
|
||||||
|
use nix::libc::getpid;
|
||||||
use pyo3::{
|
use pyo3::{
|
||||||
exceptions::PyOSError, pyclass, pyfunction, pymodule, types::PyModule,
|
exceptions::PyOSError, pyclass, pyfunction, pymodule, types::PyModule,
|
||||||
wrap_pyfunction, PyResult, Python,
|
wrap_pyfunction, PyResult, Python,
|
||||||
@@ -6,6 +8,9 @@ use pyo3::{
|
|||||||
mod blocking;
|
mod blocking;
|
||||||
use anyhow::{Error, Result};
|
use anyhow::{Error, Result};
|
||||||
use blocking::run_query;
|
use blocking::run_query;
|
||||||
|
use sysinfo::{Pid, ProcessExt, System, SystemExt};
|
||||||
|
|
||||||
|
const LOCK_FILE: &str = "/run/lqos/libreqos.lock";
|
||||||
|
|
||||||
/// Defines the Python module exports.
|
/// Defines the Python module exports.
|
||||||
/// All exported functions have to be listed here.
|
/// All exported functions have to be listed here.
|
||||||
@@ -18,6 +23,9 @@ fn liblqos_python(_py: Python, m: &PyModule) -> PyResult<()> {
|
|||||||
m.add_wrapped(wrap_pyfunction!(delete_ip_mapping))?;
|
m.add_wrapped(wrap_pyfunction!(delete_ip_mapping))?;
|
||||||
m.add_wrapped(wrap_pyfunction!(add_ip_mapping))?;
|
m.add_wrapped(wrap_pyfunction!(add_ip_mapping))?;
|
||||||
m.add_wrapped(wrap_pyfunction!(validate_shaped_devices))?;
|
m.add_wrapped(wrap_pyfunction!(validate_shaped_devices))?;
|
||||||
|
m.add_wrapped(wrap_pyfunction!(is_libre_already_running))?;
|
||||||
|
m.add_wrapped(wrap_pyfunction!(create_lock_file))?;
|
||||||
|
m.add_wrapped(wrap_pyfunction!(free_lock_file))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,3 +155,46 @@ fn validate_shaped_devices() -> PyResult<String> {
|
|||||||
}
|
}
|
||||||
Ok("".to_string())
|
Ok("".to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[pyfunction]
|
||||||
|
fn is_libre_already_running() -> PyResult<bool> {
|
||||||
|
let lock_path = Path::new(LOCK_FILE);
|
||||||
|
if lock_path.exists() {
|
||||||
|
let contents = std::fs::read_to_string(lock_path);
|
||||||
|
if let Ok(contents) = contents {
|
||||||
|
if let Ok(pid) = contents.parse::<i32>() {
|
||||||
|
let sys = System::new_all();
|
||||||
|
if let Some(process) = sys.processes().get(&Pid::from(pid)) {
|
||||||
|
if process.name().contains("python") {
|
||||||
|
return Ok(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
println!("{LOCK_FILE} did not contain a valid PID");
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
println!("Error reading contents of {LOCK_FILE}");
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pyfunction]
|
||||||
|
fn create_lock_file() -> PyResult<()> {
|
||||||
|
let pid = unsafe { getpid() };
|
||||||
|
let pid_format = format!("{pid}");
|
||||||
|
{
|
||||||
|
if let Ok(mut f) = File::create(LOCK_FILE) {
|
||||||
|
f.write_all(pid_format.as_bytes())?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pyfunction]
|
||||||
|
fn free_lock_file() -> PyResult<()> {
|
||||||
|
let _ = remove_file(LOCK_FILE); // Ignore result
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
@@ -109,7 +109,7 @@ async fn main() -> Result<()> {
|
|||||||
let server = UnixSocketServer::new().expect("Unable to spawn server");
|
let server = UnixSocketServer::new().expect("Unable to spawn server");
|
||||||
server.listen(handle_bus_requests).await
|
server.listen(handle_bus_requests).await
|
||||||
};
|
};
|
||||||
tokio::spawn(listener);
|
let handle = tokio::spawn(listener);
|
||||||
|
|
||||||
if lqos_config::LibreQoSConfig::config_exists() && lqos_config::ConfigShapedDevices::exists() {
|
if lqos_config::LibreQoSConfig::config_exists() && lqos_config::ConfigShapedDevices::exists() {
|
||||||
warn!("Since all the files exist, Launching LibreQoS.py to avoid empty queues.");
|
warn!("Since all the files exist, Launching LibreQoS.py to avoid empty queues.");
|
||||||
@@ -118,6 +118,8 @@ async fn main() -> Result<()> {
|
|||||||
warn!("ispConfig.py or ShapedDevices.csv hasn't been setup yet. Not automatically running LibreQoS.py");
|
warn!("ispConfig.py or ShapedDevices.csv hasn't been setup yet. Not automatically running LibreQoS.py");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
info!("{:?}", handle.await?);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user