]> git.proxmox.com Git - proxmox-backup.git/blame - src/api2/node/status.rs
move more tools for the client into subcrates
[proxmox-backup.git] / src / api2 / node / status.rs
CommitLineData
ed751dc2 1use std::process::Command;
33070956 2use std::path::Path;
ed751dc2
DM
3
4use anyhow::{Error, format_err, bail};
eb704648 5use serde_json::Value;
2337df7b
TL
6
7use proxmox::sys::linux::procfs;
8
ed751dc2 9use proxmox::api::{api, ApiMethod, Router, RpcEnvironment, Permission};
2337df7b 10
4805edc4
WB
11use pbs_tools::cert::CertInfo;
12
2337df7b 13use crate::api2::types::*;
ed751dc2 14use crate::config::acl::{PRIV_SYS_AUDIT, PRIV_SYS_POWER_MANAGEMENT};
2337df7b 15
398636b6
DC
16impl std::convert::From<procfs::ProcFsCPUInfo> for NodeCpuInformation {
17 fn from(info: procfs::ProcFsCPUInfo) -> Self {
18 Self {
19 model: info.model,
20 sockets: info.sockets,
21 cpus: info.cpus,
22 }
23 }
24}
25
2337df7b
TL
26#[api(
27 input: {
28 properties: {
29 node: {
30 schema: NODE_SCHEMA,
31 },
32 },
33 },
34 returns: {
eb704648 35 type: NodeStatus,
b5037fa8
DM
36 },
37 access: {
f1490da8 38 permission: &Permission::Privilege(&["system", "status"], PRIV_SYS_AUDIT, false),
b5037fa8 39 },
2337df7b
TL
40)]
41/// Read node memory, CPU and (root) disk usage
bfcef26a 42fn get_status(
2337df7b
TL
43 _param: Value,
44 _info: &ApiMethod,
45 _rpcenv: &mut dyn RpcEnvironment,
eb704648 46) -> Result<NodeStatus, Error> {
2337df7b 47 let meminfo: procfs::ProcFsMemInfo = procfs::read_meminfo()?;
eb704648
DC
48 let memory = NodeMemoryCounters {
49 total: meminfo.memtotal,
50 used: meminfo.memused,
51 free: meminfo.memfree,
52 };
2337df7b 53
398636b6
DC
54 let swap = NodeSwapCounters {
55 total: meminfo.swaptotal,
56 used: meminfo.swapused,
57 free: meminfo.swapfree,
58 };
59
eb704648
DC
60 let kstat: procfs::ProcFsStat = procfs::read_proc_stat()?;
61 let cpu = kstat.cpu;
398636b6
DC
62 let wait = kstat.iowait_percent;
63
64 let loadavg = procfs::Loadavg::read()?;
65 let loadavg = [loadavg.one(), loadavg.five(), loadavg.fifteen()];
66
67 let cpuinfo = procfs::read_cpuinfo()?;
68 let cpuinfo = cpuinfo.into();
69
70 let uname = nix::sys::utsname::uname();
71 let kversion = format!(
72 "{} {} {}",
73 uname.sysname(),
74 uname.release(),
75 uname.version()
76 );
bfcef26a 77
eb704648
DC
78 Ok(NodeStatus {
79 memory,
398636b6 80 swap,
eb704648 81 root: crate::tools::disks::disk_usage(Path::new("/"))?,
398636b6
DC
82 uptime: procfs::read_proc_uptime()?.0 as u64,
83 loadavg,
84 kversion,
85 cpuinfo,
eb704648 86 cpu,
398636b6 87 wait,
eb704648
DC
88 info: NodeInformation {
89 fingerprint: CertInfo::new()?.fingerprint()?,
bfcef26a 90 },
eb704648 91 })
2337df7b
TL
92}
93
ed751dc2
DM
94#[api(
95 protected: true,
96 input: {
97 properties: {
98 node: {
99 schema: NODE_SCHEMA,
100 },
101 command: {
102 type: NodePowerCommand,
103 },
104 }
105 },
106 access: {
107 permission: &Permission::Privilege(&["system", "status"], PRIV_SYS_POWER_MANAGEMENT, false),
108 },
109)]
110/// Reboot or shutdown the node.
111fn reboot_or_shutdown(command: NodePowerCommand) -> Result<(), Error> {
112
113 let systemctl_command = match command {
114 NodePowerCommand::Reboot => "reboot",
115 NodePowerCommand::Shutdown => "poweroff",
116 };
117
cbef49bf 118 let output = Command::new("systemctl")
ed751dc2
DM
119 .arg(systemctl_command)
120 .output()
121 .map_err(|err| format_err!("failed to execute systemctl - {}", err))?;
122
123 if !output.status.success() {
124 match output.status.code() {
125 Some(code) => {
126 let msg = String::from_utf8(output.stderr)
127 .map(|m| if m.is_empty() { String::from("no error message") } else { m })
128 .unwrap_or_else(|_| String::from("non utf8 error message (suppressed)"));
129 bail!("diff failed with status code: {} - {}", code, msg);
130 }
131 None => bail!("systemctl terminated by signal"),
132 }
133 }
134 Ok(())
135}
2337df7b 136
2337df7b 137pub const ROUTER: Router = Router::new()
bfcef26a 138 .get(&API_METHOD_GET_STATUS)
ed751dc2 139 .post(&API_METHOD_REBOOT_OR_SHUTDOWN);