diff --git a/common/src/types.rs b/common/src/types.rs index 980c88f..0d4061a 100644 --- a/common/src/types.rs +++ b/common/src/types.rs @@ -148,11 +148,18 @@ pub struct UnitStatus { pub active_state: String, pub sub_state: String, pub path: String, // FIXME: PathBuf? + pub freezer_state: String, } impl UnitStatus { pub fn is_running(&self) -> bool { - self.active_state == "active" && self.load_state == "loaded" && self.sub_state == "running" + !self.is_paused() + && self.active_state == "active" + && self.load_state == "loaded" + && self.sub_state == "running" + } + pub fn is_paused(&self) -> bool { + self.freezer_state == "frozen" } pub fn is_exitted(&self) -> bool { self.active_state == "inactive" @@ -171,6 +178,7 @@ impl TryFrom for UnitStatus { active_state: us.active_state, sub_state: "stub".into(), path: us.path, + freezer_state: "bogus".into(), }) } } diff --git a/nixos/tests/admin.nix b/nixos/tests/admin.nix index d4ca70f..eadf308 100644 --- a/nixos/tests/admin.nix +++ b/nixos/tests/admin.nix @@ -308,6 +308,12 @@ in retry(func, timeout=30) # End of borrowed code + def by_name(name, js): + for each in js: + if each["name"] == name: + return each + raise KeyError(name) + import time with subtest("setup services"): hostvm.wait_for_unit("givc-ghaf-host.service") @@ -352,8 +358,24 @@ in print(hostvm.succeed("${cli} --addr ${nodes.adminvm.config.givc.admin.addr} --port ${nodes.adminvm.config.givc.admin.port} --cacert ${nodes.hostvm.givc.host.tls.caCertPath} --cert ${nodes.hostvm.givc.host.tls.certPath} --key ${nodes.hostvm.givc.host.tls.keyPath} ${if tls then "" else "--notls"} --name ${nodes.adminvm.config.givc.admin.name} start --vm chromium-vm foot")) wait_for_window("ghaf@appvm") - with subtest("stop application"): + with subtest("pause/resume/stop application"): appvm.succeed("pgrep foot") + print(hostvm.succeed("${cli} --addr ${nodes.adminvm.config.givc.admin.addr} --port ${nodes.adminvm.config.givc.admin.port} --cacert ${nodes.hostvm.givc.host.tls.caCertPath} --cert ${nodes.hostvm.givc.host.tls.certPath} --key ${nodes.hostvm.givc.host.tls.keyPath} ${if tls then "" else "--notls"} --name ${nodes.adminvm.config.givc.admin.name} pause foot@1.service")) + time.sleep(20) + js = hostvm.succeed("${cli} --addr ${nodes.adminvm.config.givc.admin.addr} --port ${nodes.adminvm.config.givc.admin.port} --cacert ${nodes.hostvm.givc.host.tls.caCertPath} --cert ${nodes.hostvm.givc.host.tls.certPath} --key ${nodes.hostvm.givc.host.tls.keyPath} ${if tls then "" else "--notls"} --name ${nodes.adminvm.config.givc.admin.name} query-list --as-json 2>/dev/null") + foot = by_name("foot@1.service", json.loads(js)) + assert foot["status"] == "Paused" + res = appvm.succeed("cat /sys/fs/cgroup/user.slice/user-1000.slice/user@1000.service/app.slice/app-foot.slice/foot@1.service/cgroup.events") + assert "frozen 1" in res + + print(hostvm.succeed("${cli} --addr ${nodes.adminvm.config.givc.admin.addr} --port ${nodes.adminvm.config.givc.admin.port} --cacert ${nodes.hostvm.givc.host.tls.caCertPath} --cert ${nodes.hostvm.givc.host.tls.certPath} --key ${nodes.hostvm.givc.host.tls.keyPath} ${if tls then "" else "--notls"} --name ${nodes.adminvm.config.givc.admin.name} resume foot@1.service")) + time.sleep(20) + res = appvm.succeed("cat /sys/fs/cgroup/user.slice/user-1000.slice/user@1000.service/app.slice/app-foot.slice/foot@1.service/cgroup.events") + assert "frozen 0" in res + js = hostvm.succeed("${cli} --addr ${nodes.adminvm.config.givc.admin.addr} --port ${nodes.adminvm.config.givc.admin.port} --cacert ${nodes.hostvm.givc.host.tls.caCertPath} --cert ${nodes.hostvm.givc.host.tls.certPath} --key ${nodes.hostvm.givc.host.tls.keyPath} ${if tls then "" else "--notls"} --name ${nodes.adminvm.config.givc.admin.name} query-list --as-json 2>/dev/null") + foot = by_name("foot@1.service", json.loads(js)) + assert foot["status"] == "Running" + print(hostvm.succeed("${cli} --addr ${nodes.adminvm.config.givc.admin.addr} --port ${nodes.adminvm.config.givc.admin.port} --cacert ${nodes.hostvm.givc.host.tls.caCertPath} --cert ${nodes.hostvm.givc.host.tls.certPath} --key ${nodes.hostvm.givc.host.tls.keyPath} ${if tls then "" else "--notls"} --name ${nodes.adminvm.config.givc.admin.name} stop foot@1.service")) appvm.fail("pgrep foot") diff --git a/src/admin/entry.rs b/src/admin/entry.rs index 068fa9b..30f2b87 100644 --- a/src/admin/entry.rs +++ b/src/admin/entry.rs @@ -55,6 +55,7 @@ impl RegistryEntry { load_state: "loaded".to_string(), sub_state: "bogus".to_string(), path: "bogus".to_string(), + freezer_state: "bogus".to_string(), }, placement: Placement::Endpoint(EndpointEntry { address: EndpointAddress::Tcp { @@ -97,6 +98,8 @@ impl From for QueryResult { fn from(val: RegistryEntry) -> Self { let status = if val.status.is_running() { VMStatus::Running + } else if val.status.is_paused() { + VMStatus::Paused } else { VMStatus::PoweredOff }; diff --git a/src/bin/givc-agent.rs b/src/bin/givc-agent.rs index 4b7da6b..3063307 100644 --- a/src/bin/givc-agent.rs +++ b/src/bin/givc-agent.rs @@ -103,6 +103,7 @@ async fn main() -> std::result::Result<(), Box> { active_state: String::from("bogus"), sub_state: String::from("bogus"), path: String::from("bogus"), + freezer_state: String::from("bogus"), }; let admin_tls = tls.clone().map(|tls| (cli.admin_server_name, tls)); diff --git a/src/lib.rs b/src/lib.rs index 406ac0d..b4b136c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,16 +20,17 @@ pub fn trace_init() -> anyhow::Result<()> { .max_level_hint() .map_or_else(|| false, |level| level >= Level::DEBUG); - let stdout = tracing_subscriber::fmt::layer() + let output = tracing_subscriber::fmt::layer() + .with_writer(std::io::stderr) .with_target(is_debug_log_level) .with_file(is_debug_log_level) .with_line_number(is_debug_log_level) .with_thread_ids(is_debug_log_level); - let stdout = if is_debug_log_level { - stdout.pretty().boxed() + let output = if is_debug_log_level { + output.pretty().boxed() } else { - stdout.boxed() + output.boxed() }; // enable journald logging only on release to avoid log spam on dev machines @@ -40,7 +41,7 @@ pub fn trace_init() -> anyhow::Result<()> { let subscriber = tracing_subscriber::registry() .with(journald.with_filter(LevelFilter::INFO)) - .with(stdout.with_filter(env_filter)); + .with(output.with_filter(env_filter)); tracing::subscriber::set_global_default(subscriber) .expect("tracing shouldn't already have been set up"); diff --git a/src/systemd_api/client.rs b/src/systemd_api/client.rs index e67271a..2900ce4 100644 --- a/src/systemd_api/client.rs +++ b/src/systemd_api/client.rs @@ -36,6 +36,7 @@ impl SystemDClient { active_state: status.active_state, sub_state: status.sub_state, path: status.path, + freezer_state: status.freezer_state, }) }