From ed751dc2ab5326eb47e2e3ad30dbdbf1c6afc1a2 Mon Sep 17 00:00:00 2001 From: Dietmar Maurer Date: Thu, 30 Apr 2020 11:52:40 +0200 Subject: [PATCH] src/api2/node/status.rs: rework api, implement reboot and shutdown --- src/api2/node/status.rs | 60 +++++++++++++++++++++++++++++++++-------- src/api2/types.rs | 11 ++++++++ 2 files changed, 60 insertions(+), 11 deletions(-) diff --git a/src/api2/node/status.rs b/src/api2/node/status.rs index 3b966d63..5af49708 100644 --- a/src/api2/node/status.rs +++ b/src/api2/node/status.rs @@ -1,13 +1,14 @@ -use anyhow::{Error}; +use std::process::Command; + +use anyhow::{Error, format_err, bail}; use serde_json::{json, Value}; use proxmox::sys::linux::procfs; -use proxmox::api::{api, ApiMethod, Router, RpcEnvironment, SubdirMap, Permission}; -use proxmox::list_subdirs_api_method; +use proxmox::api::{api, ApiMethod, Router, RpcEnvironment, Permission}; use crate::api2::types::*; -use crate::config::acl::PRIV_SYS_AUDIT; +use crate::config::acl::{PRIV_SYS_AUDIT, PRIV_SYS_POWER_MANAGEMENT}; #[api( input: { @@ -70,12 +71,49 @@ fn get_usage( })) } -pub const USAGE_ROUTER: Router = Router::new() - .get(&API_METHOD_GET_USAGE); +#[api( + protected: true, + input: { + properties: { + node: { + schema: NODE_SCHEMA, + }, + command: { + type: NodePowerCommand, + }, + } + }, + access: { + permission: &Permission::Privilege(&["system", "status"], PRIV_SYS_POWER_MANAGEMENT, false), + }, +)] +/// Reboot or shutdown the node. +fn reboot_or_shutdown(command: NodePowerCommand) -> Result<(), Error> { + + let systemctl_command = match command { + NodePowerCommand::Reboot => "reboot", + NodePowerCommand::Shutdown => "poweroff", + }; + + let output = Command::new("/bin/systemctl") + .arg(systemctl_command) + .output() + .map_err(|err| format_err!("failed to execute systemctl - {}", err))?; + + if !output.status.success() { + match output.status.code() { + Some(code) => { + let msg = String::from_utf8(output.stderr) + .map(|m| if m.is_empty() { String::from("no error message") } else { m }) + .unwrap_or_else(|_| String::from("non utf8 error message (suppressed)")); + bail!("diff failed with status code: {} - {}", code, msg); + } + None => bail!("systemctl terminated by signal"), + } + } + Ok(()) +} -pub const SUBDIRS: SubdirMap = &[ - ("usage", &USAGE_ROUTER), -]; pub const ROUTER: Router = Router::new() - .get(&list_subdirs_api_method!(SUBDIRS)) - .subdirs(SUBDIRS); + .get(&API_METHOD_GET_USAGE) + .post(&API_METHOD_REBOOT_OR_SHUTDOWN); diff --git a/src/api2/types.rs b/src/api2/types.rs index f5c32d9d..bfd94601 100644 --- a/src/api2/types.rs +++ b/src/api2/types.rs @@ -499,6 +499,17 @@ pub struct TaskListItem { pub status: Option, } +#[api()] +#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "lowercase")] +/// Node Power command type. +pub enum NodePowerCommand { + /// Restart the server + Reboot, + /// Shutdown the server + Shutdown, +} + #[api()] #[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "lowercase")]