diff --git a/migrations/01_init.sql b/migrations/01_init.sql index 6f1280d..e349a26 100644 --- a/migrations/01_init.sql +++ b/migrations/01_init.sql @@ -5,6 +5,13 @@ CREATE TABLE IF NOT EXISTS global_action ( next_run INTEGER DEFAULT 0 NOT NULL ); +CREATE TABLE IF NOT EXISTS jail_action ( + name TEXT NOT NULL, + jail_name TEXT NOT NULL, + next_run INTEGER DEFAULT 0 NOT NULL, + PRIMARY KEY (name, jail_name) +); + CREATE TABLE IF NOT EXISTS local_action ( name TEXT NOT NULL, jail_name TEXT NOT NULL, diff --git a/src/action/jail.rs b/src/action/jail.rs new file mode 100644 index 0000000..dc9db69 --- /dev/null +++ b/src/action/jail.rs @@ -0,0 +1,40 @@ +use std::process::Command; +use std::time::Duration; +use std::time::SystemTime; + +use crate::action::ACTION_BUILD; +use crate::db::DbHandle; +use crate::db::DbJailAction; + +pub(crate) const ACTION_UPDATE_JAIL: &str = "update_jail"; +const ACTION_UPDATE_JAIL_INTERVAL: u64 = 604800; + +pub(crate) fn update_jail( + db_conn: &mut DbHandle, + action: &DbJailAction, +) -> Result<(), Box> { + println!("Updating jail {}.", action.jail_name.as_str()); + Command::new("poudriere") + .arg("jail") + .arg("-j") + .arg(action.jail_name.as_str()) + .arg("-u") + .status()? + .exit_ok()?; + let next_run = (SystemTime::now() + Duration::from_secs(ACTION_UPDATE_JAIL_INTERVAL)) + .duration_since(SystemTime::UNIX_EPOCH)? + .as_secs(); + + let tx = db_conn.conn.transaction()?; + tx.execute( + "UPDATE jail_action SET next_run=$1 WHERE name=$2 AND jail_name=$3", + (next_run, ACTION_UPDATE_JAIL, action.jail_name.as_str()), + )?; + // Since we just updated the jail, force a build ASAP since it may need to rebuild everything. + tx.execute( + "UPDATE local_action SET next_run=0 WHERE name=$1 AND jail_name=$2", + (ACTION_BUILD, action.jail_name.as_str()), + )?; + tx.commit()?; + Ok(()) +} diff --git a/src/action/mod.rs b/src/action/mod.rs index 9c831b1..e6c25a3 100644 --- a/src/action/mod.rs +++ b/src/action/mod.rs @@ -1,10 +1,13 @@ mod build; mod cleanup; +mod jail; mod ports_tree; pub(crate) use build::build; pub(crate) use build::ACTION_BUILD; pub(crate) use cleanup::cleanup; pub(crate) use cleanup::ACTION_CLEANUP; +pub(crate) use jail::update_jail; +pub(crate) use jail::ACTION_UPDATE_JAIL; pub(crate) use ports_tree::update_ports_tree; pub(crate) use ports_tree::ACTION_UPDATE_PORTS_TREE; diff --git a/src/db/init.rs b/src/db/init.rs index 07c9cb2..6c831b0 100644 --- a/src/db/init.rs +++ b/src/db/init.rs @@ -6,6 +6,7 @@ use rusqlite::params; use rusqlite::Connection; use super::DbGlobalAction; +use super::DbJailAction; use super::DbLocalAction; static DB_INIT_QUERY: &str = include_str!("../../migrations/01_init.sql"); @@ -43,6 +44,27 @@ impl DbHandle { Ok(rows) } + pub(crate) fn get_pending_jail_actions( + &mut self, + ) -> Result, Box> { + let now = SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH)? + .as_secs(); + let mut stmt = self + .conn + .prepare("SELECT name, jail_name, next_run FROM jail_action WHERE next_run <= $1")?; + let rows = stmt + .query_map(params![now], |row| { + Ok(DbJailAction { + name: row.get(0)?, + jail_name: row.get(1)?, + next_run: row.get(2)?, + }) + })? + .collect::, _>>()?; + Ok(rows) + } + pub(crate) fn get_pending_local_actions( &mut self, ) -> Result, Box> { @@ -71,7 +93,7 @@ impl DbHandle { ) -> Result> { let now = SystemTime::now(); let mut stmt = self.conn.prepare( - "WITH next_runs AS (SELECT next_run FROM global_action UNION SELECT next_run FROM local_action) SELECT next_run FROM next_runs ORDER BY next_run ASC", + "WITH next_runs AS (SELECT next_run FROM global_action UNION SELECT next_run FROM jail_action UNION SELECT next_run FROM local_action) SELECT min(next_run) FROM next_runs;", )?; let rows = stmt .query_map(params![], |row| row.get(0))? diff --git a/src/db/mod.rs b/src/db/mod.rs index 4f8be4f..808ac68 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -3,4 +3,5 @@ mod types; pub(crate) use init::DbHandle; pub(crate) use types::DbGlobalAction; +pub(crate) use types::DbJailAction; pub(crate) use types::DbLocalAction; diff --git a/src/db/types.rs b/src/db/types.rs index 2b6654c..fc86836 100644 --- a/src/db/types.rs +++ b/src/db/types.rs @@ -4,6 +4,13 @@ pub(crate) struct DbGlobalAction { pub(crate) next_run: i64, } +pub(crate) struct DbJailAction { + pub(crate) name: String, + pub(crate) jail_name: String, + #[allow(dead_code)] + pub(crate) next_run: i64, +} + pub(crate) struct DbLocalAction { pub(crate) name: String, pub(crate) jail_name: String, diff --git a/src/main.rs b/src/main.rs index 811bc54..855cf92 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,9 +3,11 @@ use std::{thread, time}; use crate::action::build; use crate::action::cleanup; +use crate::action::update_jail; use crate::action::update_ports_tree; use crate::action::ACTION_BUILD; use crate::action::ACTION_CLEANUP; +use crate::action::ACTION_UPDATE_JAIL; use crate::action::ACTION_UPDATE_PORTS_TREE; mod action; @@ -32,6 +34,17 @@ fn main() -> Result<(), Box> { }; } + for pending_jail_action in db_conn.get_pending_jail_actions()? { + match pending_jail_action.name.as_str() { + ACTION_UPDATE_JAIL => { + update_jail(&mut db_conn, &pending_jail_action)?; + } + _ => { + panic!("Unknown jail action: {}", pending_jail_action.name); + } + } + } + for pending_local_action in db_conn.get_pending_local_actions()? { match pending_local_action.name.as_str() { ACTION_BUILD => {