* [pdm-devel] [PATCH datacenter-manager 0/4] system report via admin cli or API
@ 2025-12-01 12:58 Lukas Wagner
2025-12-01 12:58 ` [pdm-devel] [PATCH datacenter-manager 1/4] server: add system report implementation Lukas Wagner
` (6 more replies)
0 siblings, 7 replies; 11+ messages in thread
From: Lukas Wagner @ 2025-12-01 12:58 UTC (permalink / raw)
To: pdm-devel
Still missing the UI integration.
Lukas Wagner (4):
server: add system report implementation
api: add system report API
cli: admin: add 'report' command to generate a system report
pdm-client: add bindings for system report generation
cli/admin/src/main.rs | 13 +++
lib/pdm-client/src/lib.rs | 10 ++
server/src/api/nodes/mod.rs | 2 +
server/src/api/nodes/report.rs | 32 ++++++
server/src/lib.rs | 1 +
server/src/report.rs | 195 +++++++++++++++++++++++++++++++++
6 files changed, 253 insertions(+)
create mode 100644 server/src/api/nodes/report.rs
create mode 100644 server/src/report.rs
--
2.47.3
_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel
^ permalink raw reply [flat|nested] 11+ messages in thread* [pdm-devel] [PATCH datacenter-manager 1/4] server: add system report implementation 2025-12-01 12:58 [pdm-devel] [PATCH datacenter-manager 0/4] system report via admin cli or API Lukas Wagner @ 2025-12-01 12:58 ` Lukas Wagner 2025-12-01 14:55 ` Shannon Sterz 2025-12-01 12:58 ` [pdm-devel] [PATCH datacenter-manager 2/4] api: add system report API Lukas Wagner ` (5 subsequent siblings) 6 siblings, 1 reply; 11+ messages in thread From: Lukas Wagner @ 2025-12-01 12:58 UTC (permalink / raw) To: pdm-devel This code was taken from PBS and then adapted for PDM. While it could make sense to refactor and then share some of the helper functions with PBS, the benefit is rather small (the helpers are relatively trivial) and now is not the best time for it. The risk and potential consequences of diverging implementations is small. Signed-off-by: Lukas Wagner <l.wagner@proxmox.com> --- server/src/lib.rs | 1 + server/src/report.rs | 195 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 196 insertions(+) create mode 100644 server/src/report.rs diff --git a/server/src/lib.rs b/server/src/lib.rs index bd8660a7..5ed10d69 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -11,6 +11,7 @@ pub mod parallel_fetcher; pub mod remote_cache; pub mod remote_tasks; pub mod remote_updates; +pub mod report; pub mod resource_cache; pub mod task_utils; pub mod views; diff --git a/server/src/report.rs b/server/src/report.rs new file mode 100644 index 00000000..247db4f1 --- /dev/null +++ b/server/src/report.rs @@ -0,0 +1,195 @@ +use std::fmt::Write; +use std::path::Path; +use std::process::Command; + +// TODO: This was copied from PBS. Might make sense to refactor these a little +// bit and move them a `proxmox-system-report` crate or something. + +fn get_top_processes() -> String { + let (exe, args) = ("top", vec!["-b", "-c", "-w512", "-n", "1", "-o", "TIME"]); + let output = Command::new(exe).args(&args).output(); + let output = match output { + Ok(output) => String::from_utf8_lossy(&output.stdout).to_string(), + Err(err) => err.to_string(), + }; + let output = output.lines().take(30).collect::<Vec<&str>>().join("\n"); + format!("$ `{exe} {}`\n```\n{output}\n```", args.join(" ")) +} + +fn files() -> Vec<(&'static str, Vec<&'static str>)> { + vec![ + ( + "General System Info", + vec![ + "/etc/hostname", + "/etc/hosts", + "/etc/network/interfaces", + "/etc/apt/sources.list", + "/etc/apt/sources.list.d/", + "/proc/pressure/", + ], + ), + ( + "User & Access", + vec![ + "/etc/proxmox-datacenter-manager/access/user.cfg", + "/etc/proxmox-datacenter-manager/access/acl.cfg", + ], + ), + ( + "Others", + vec![ + "/etc/proxmox-datacenter-manager/node.cfg", + "/etc/proxmox-datacenter-manager/views.cfg", + ], + ), + ] +} + +fn commands() -> Vec<(&'static str, Vec<&'static str>)> { + vec![ + // ("<command>", vec![<arg [, arg]>]) + ("date", vec!["-R"]), + ( + "proxmox-datacenter-manager-admin", + vec!["versions", "--verbose"], + ), + ("proxmox-datacenter-manager-admin", vec!["remote", "list"]), + // FIXME: Does not exist yet. + // ("proxmox-datacenter-manager-admin", vec!["subscription", "get"]), + ("proxmox-boot-tool", vec!["status"]), + ("df", vec!["-h"]), + ( + "lsblk", + vec![ + "--ascii", + "-M", + "-o", + "+HOTPLUG,ROTA,PHY-SEC,FSTYPE,MODEL,TRAN", + ], + ), + ("ls", vec!["-l", "/dev/disk/by-id", "/dev/disk/by-path"]), + ("zpool", vec!["status"]), + ("zfs", vec!["list"]), + ("arcstat", vec![]), + ] +} + +// (description, function()) +type FunctionMapping = (&'static str, fn() -> String); + +fn function_calls() -> Vec<FunctionMapping> { + vec![("System Load & Uptime", get_top_processes)] +} + +fn get_file_content(file: impl AsRef<Path>) -> String { + use proxmox_sys::fs::file_read_optional_string; + let content = match file_read_optional_string(&file) { + Ok(Some(content)) => content, + Ok(None) => String::from("# file does not exist"), + Err(err) => err.to_string(), + }; + let file_name = file.as_ref().display(); + format!("`$ cat '{file_name}'`\n```\n{}\n```", content.trim_end()) +} + +fn get_directory_content(path: impl AsRef<Path>) -> String { + let read_dir_iter = match std::fs::read_dir(&path) { + Ok(iter) => iter, + Err(err) => { + return format!( + "`$ cat '{}*'`\n```\n# read dir failed - {err}\n```", + path.as_ref().display(), + ); + } + }; + let mut out = String::new(); + let mut first = true; + for entry in read_dir_iter { + let entry = match entry { + Ok(entry) => entry, + Err(err) => { + let _ = writeln!(out, "error during read-dir - {err}"); + continue; + } + }; + let path = entry.path(); + if path.is_file() { + if first { + let _ = writeln!(out, "{}", get_file_content(path)); + first = false; + } else { + let _ = writeln!(out, "\n{}", get_file_content(path)); + } + } else { + let _ = writeln!(out, "skipping sub-directory `{}`", path.display()); + } + } + out +} + +fn get_command_output(exe: &str, args: &Vec<&str>) -> String { + let output = Command::new(exe) + .env("PROXMOX_OUTPUT_NO_BORDER", "1") + .args(args) + .output(); + let output = match output { + Ok(output) => { + let mut out = String::from_utf8_lossy(&output.stdout) + .trim_end() + .to_string(); + let stderr = String::from_utf8_lossy(&output.stderr) + .trim_end() + .to_string(); + if !stderr.is_empty() { + let _ = writeln!(out, "\n```\nSTDERR:\n```\n{stderr}"); + } + out + } + Err(err) => err.to_string(), + }; + format!("$ `{exe} {}`\n```\n{output}\n```", args.join(" ")) +} + +pub fn generate_report() -> String { + let file_contents = files() + .iter() + .map(|group| { + let (group, files) = group; + let group_content = files + .iter() + .map(|file_name| { + let path = Path::new(file_name); + if path.is_dir() { + get_directory_content(path) + } else { + get_file_content(file_name) + } + }) + .collect::<Vec<String>>() + .join("\n\n"); + + format!("### {group}\n\n{group_content}") + }) + .collect::<Vec<String>>() + .join("\n\n"); + + let command_outputs = commands() + .iter() + .map(|(command, args)| get_command_output(command, args)) + .collect::<Vec<String>>() + .join("\n\n"); + + let function_outputs = function_calls() + .iter() + .map(|(desc, function)| { + let output = function(); + format!("#### {desc}\n{}\n", output.trim_end()) + }) + .collect::<Vec<String>>() + .join("\n\n"); + + format!( + "## FILES\n\n{file_contents}\n## COMMANDS\n\n{command_outputs}\n## FUNCTIONS\n\n{function_outputs}\n" + ) +} -- 2.47.3 _______________________________________________ pdm-devel mailing list pdm-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [pdm-devel] [PATCH datacenter-manager 1/4] server: add system report implementation 2025-12-01 12:58 ` [pdm-devel] [PATCH datacenter-manager 1/4] server: add system report implementation Lukas Wagner @ 2025-12-01 14:55 ` Shannon Sterz 2025-12-01 15:06 ` Lukas Wagner 0 siblings, 1 reply; 11+ messages in thread From: Shannon Sterz @ 2025-12-01 14:55 UTC (permalink / raw) To: Lukas Wagner; +Cc: Proxmox Datacenter Manager development discussion On Mon Dec 1, 2025 at 1:58 PM CET, Lukas Wagner wrote: > This code was taken from PBS and then adapted for PDM. While it could > make sense to refactor and then share some of the helper functions with > PBS, the benefit is rather small (the helpers are relatively trivial) > and now is not the best time for it. The risk and potential consequences > of diverging implementations is small. > > Signed-off-by: Lukas Wagner <l.wagner@proxmox.com> > --- > server/src/lib.rs | 1 + > server/src/report.rs | 195 +++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 196 insertions(+) > create mode 100644 server/src/report.rs > > diff --git a/server/src/lib.rs b/server/src/lib.rs > index bd8660a7..5ed10d69 100644 > --- a/server/src/lib.rs > +++ b/server/src/lib.rs > @@ -11,6 +11,7 @@ pub mod parallel_fetcher; > pub mod remote_cache; > pub mod remote_tasks; > pub mod remote_updates; > +pub mod report; > pub mod resource_cache; > pub mod task_utils; > pub mod views; > diff --git a/server/src/report.rs b/server/src/report.rs > new file mode 100644 > index 00000000..247db4f1 > --- /dev/null > +++ b/server/src/report.rs > @@ -0,0 +1,195 @@ > +use std::fmt::Write; > +use std::path::Path; > +use std::process::Command; > + > +// TODO: This was copied from PBS. Might make sense to refactor these a little > +// bit and move them a `proxmox-system-report` crate or something. > + > +fn get_top_processes() -> String { > + let (exe, args) = ("top", vec!["-b", "-c", "-w512", "-n", "1", "-o", "TIME"]); > + let output = Command::new(exe).args(&args).output(); > + let output = match output { > + Ok(output) => String::from_utf8_lossy(&output.stdout).to_string(), > + Err(err) => err.to_string(), > + }; > + let output = output.lines().take(30).collect::<Vec<&str>>().join("\n"); > + format!("$ `{exe} {}`\n```\n{output}\n```", args.join(" ")) > +} > + > +fn files() -> Vec<(&'static str, Vec<&'static str>)> { > + vec![ > + ( > + "General System Info", > + vec![ > + "/etc/hostname", > + "/etc/hosts", > + "/etc/network/interfaces", > + "/etc/apt/sources.list", > + "/etc/apt/sources.list.d/", > + "/proc/pressure/", > + ], > + ), > + ( > + "User & Access", > + vec![ > + "/etc/proxmox-datacenter-manager/access/user.cfg", > + "/etc/proxmox-datacenter-manager/access/acl.cfg", > + ], > + ), > + ( > + "Others", > + vec![ > + "/etc/proxmox-datacenter-manager/node.cfg", > + "/etc/proxmox-datacenter-manager/views.cfg", hm the only thing here is that layout descriptions could become rather long and i'm not sure how useful they are for support reasons (filters more so). however, not too much of an issue imo. > + ], > + ), > + ] > +} > + > +fn commands() -> Vec<(&'static str, Vec<&'static str>)> { > + vec![ > + // ("<command>", vec![<arg [, arg]>]) > + ("date", vec!["-R"]), > + ( > + "proxmox-datacenter-manager-admin", > + vec!["versions", "--verbose"], > + ), > + ("proxmox-datacenter-manager-admin", vec!["remote", "list"]), > + // FIXME: Does not exist yet. > + // ("proxmox-datacenter-manager-admin", vec!["subscription", "get"]), > + ("proxmox-boot-tool", vec!["status"]), > + ("df", vec!["-h"]), > + ( > + "lsblk", > + vec![ > + "--ascii", > + "-M", > + "-o", > + "+HOTPLUG,ROTA,PHY-SEC,FSTYPE,MODEL,TRAN", > + ], > + ), > + ("ls", vec!["-l", "/dev/disk/by-id", "/dev/disk/by-path"]), > + ("zpool", vec!["status"]), > + ("zfs", vec!["list"]), > + ("arcstat", vec![]), > + ] > +} > + > +// (description, function()) > +type FunctionMapping = (&'static str, fn() -> String); > + > +fn function_calls() -> Vec<FunctionMapping> { > + vec![("System Load & Uptime", get_top_processes)] > +} a little confused why this gets its own category. `top` usually appears more toward the top of our reports, this puts it on the very bottom. also `get_top_processes` essentially also just calls a command, so not sure why this is separated out. > + > +fn get_file_content(file: impl AsRef<Path>) -> String { > + use proxmox_sys::fs::file_read_optional_string; > + let content = match file_read_optional_string(&file) { > + Ok(Some(content)) => content, > + Ok(None) => String::from("# file does not exist"), > + Err(err) => err.to_string(), > + }; > + let file_name = file.as_ref().display(); > + format!("`$ cat '{file_name}'`\n```\n{}\n```", content.trim_end()) > +} > + > +fn get_directory_content(path: impl AsRef<Path>) -> String { > + let read_dir_iter = match std::fs::read_dir(&path) { > + Ok(iter) => iter, > + Err(err) => { > + return format!( > + "`$ cat '{}*'`\n```\n# read dir failed - {err}\n```", > + path.as_ref().display(), > + ); > + } > + }; > + let mut out = String::new(); > + let mut first = true; > + for entry in read_dir_iter { > + let entry = match entry { > + Ok(entry) => entry, > + Err(err) => { > + let _ = writeln!(out, "error during read-dir - {err}"); > + continue; > + } > + }; > + let path = entry.path(); > + if path.is_file() { > + if first { > + let _ = writeln!(out, "{}", get_file_content(path)); > + first = false; > + } else { > + let _ = writeln!(out, "\n{}", get_file_content(path)); > + } > + } else { > + let _ = writeln!(out, "skipping sub-directory `{}`", path.display()); > + } > + } > + out > +} > + > +fn get_command_output(exe: &str, args: &Vec<&str>) -> String { > + let output = Command::new(exe) > + .env("PROXMOX_OUTPUT_NO_BORDER", "1") > + .args(args) > + .output(); > + let output = match output { > + Ok(output) => { > + let mut out = String::from_utf8_lossy(&output.stdout) > + .trim_end() > + .to_string(); > + let stderr = String::from_utf8_lossy(&output.stderr) > + .trim_end() > + .to_string(); > + if !stderr.is_empty() { > + let _ = writeln!(out, "\n```\nSTDERR:\n```\n{stderr}"); > + } > + out > + } > + Err(err) => err.to_string(), > + }; > + format!("$ `{exe} {}`\n```\n{output}\n```", args.join(" ")) > +} > + > +pub fn generate_report() -> String { > + let file_contents = files() > + .iter() > + .map(|group| { > + let (group, files) = group; > + let group_content = files > + .iter() > + .map(|file_name| { > + let path = Path::new(file_name); > + if path.is_dir() { > + get_directory_content(path) > + } else { > + get_file_content(file_name) > + } > + }) > + .collect::<Vec<String>>() > + .join("\n\n"); > + > + format!("### {group}\n\n{group_content}") > + }) > + .collect::<Vec<String>>() > + .join("\n\n"); > + > + let command_outputs = commands() > + .iter() > + .map(|(command, args)| get_command_output(command, args)) > + .collect::<Vec<String>>() > + .join("\n\n"); > + > + let function_outputs = function_calls() > + .iter() > + .map(|(desc, function)| { > + let output = function(); > + format!("#### {desc}\n{}\n", output.trim_end()) > + }) > + .collect::<Vec<String>>() > + .join("\n\n"); > + > + format!( > + "## FILES\n\n{file_contents}\n## COMMANDS\n\n{command_outputs}\n## FUNCTIONS\n\n{function_outputs}\n" > + ) > +} _______________________________________________ pdm-devel mailing list pdm-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [pdm-devel] [PATCH datacenter-manager 1/4] server: add system report implementation 2025-12-01 14:55 ` Shannon Sterz @ 2025-12-01 15:06 ` Lukas Wagner 0 siblings, 0 replies; 11+ messages in thread From: Lukas Wagner @ 2025-12-01 15:06 UTC (permalink / raw) To: Shannon Sterz, Lukas Wagner Cc: Proxmox Datacenter Manager development discussion On Mon Dec 1, 2025 at 3:55 PM CET, Shannon Sterz wrote: > On Mon Dec 1, 2025 at 1:58 PM CET, Lukas Wagner wrote: >> This code was taken from PBS and then adapted for PDM. While it could >> make sense to refactor and then share some of the helper functions with >> PBS, the benefit is rather small (the helpers are relatively trivial) >> and now is not the best time for it. The risk and potential consequences >> of diverging implementations is small. >> >> Signed-off-by: Lukas Wagner <l.wagner@proxmox.com> >> --- >> server/src/lib.rs | 1 + >> server/src/report.rs | 195 +++++++++++++++++++++++++++++++++++++++++++ >> 2 files changed, 196 insertions(+) >> create mode 100644 server/src/report.rs >> >> diff --git a/server/src/lib.rs b/server/src/lib.rs >> index bd8660a7..5ed10d69 100644 >> --- a/server/src/lib.rs >> +++ b/server/src/lib.rs >> @@ -11,6 +11,7 @@ pub mod parallel_fetcher; >> pub mod remote_cache; >> pub mod remote_tasks; >> pub mod remote_updates; >> +pub mod report; >> pub mod resource_cache; >> pub mod task_utils; >> pub mod views; >> diff --git a/server/src/report.rs b/server/src/report.rs >> new file mode 100644 >> index 00000000..247db4f1 >> --- /dev/null >> +++ b/server/src/report.rs >> @@ -0,0 +1,195 @@ >> +use std::fmt::Write; >> +use std::path::Path; >> +use std::process::Command; >> + >> +// TODO: This was copied from PBS. Might make sense to refactor these a little >> +// bit and move them a `proxmox-system-report` crate or something. >> + >> +fn get_top_processes() -> String { >> + let (exe, args) = ("top", vec!["-b", "-c", "-w512", "-n", "1", "-o", "TIME"]); >> + let output = Command::new(exe).args(&args).output(); >> + let output = match output { >> + Ok(output) => String::from_utf8_lossy(&output.stdout).to_string(), >> + Err(err) => err.to_string(), >> + }; >> + let output = output.lines().take(30).collect::<Vec<&str>>().join("\n"); >> + format!("$ `{exe} {}`\n```\n{output}\n```", args.join(" ")) >> +} >> + >> +fn files() -> Vec<(&'static str, Vec<&'static str>)> { >> + vec![ >> + ( >> + "General System Info", >> + vec![ >> + "/etc/hostname", >> + "/etc/hosts", >> + "/etc/network/interfaces", >> + "/etc/apt/sources.list", >> + "/etc/apt/sources.list.d/", >> + "/proc/pressure/", >> + ], >> + ), >> + ( >> + "User & Access", >> + vec![ >> + "/etc/proxmox-datacenter-manager/access/user.cfg", >> + "/etc/proxmox-datacenter-manager/access/acl.cfg", >> + ], >> + ), >> + ( >> + "Others", >> + vec![ >> + "/etc/proxmox-datacenter-manager/node.cfg", >> + "/etc/proxmox-datacenter-manager/views.cfg", > > hm the only thing here is that layout descriptions could become rather > long and i'm not sure how useful they are for support reasons (filters > more so). however, not too much of an issue imo. > >> + ], >> + ), >> + ] >> +} >> + >> +fn commands() -> Vec<(&'static str, Vec<&'static str>)> { >> + vec![ >> + // ("<command>", vec![<arg [, arg]>]) >> + ("date", vec!["-R"]), >> + ( >> + "proxmox-datacenter-manager-admin", >> + vec!["versions", "--verbose"], >> + ), >> + ("proxmox-datacenter-manager-admin", vec!["remote", "list"]), >> + // FIXME: Does not exist yet. >> + // ("proxmox-datacenter-manager-admin", vec!["subscription", "get"]), >> + ("proxmox-boot-tool", vec!["status"]), >> + ("df", vec!["-h"]), >> + ( >> + "lsblk", >> + vec![ >> + "--ascii", >> + "-M", >> + "-o", >> + "+HOTPLUG,ROTA,PHY-SEC,FSTYPE,MODEL,TRAN", >> + ], >> + ), >> + ("ls", vec!["-l", "/dev/disk/by-id", "/dev/disk/by-path"]), >> + ("zpool", vec!["status"]), >> + ("zfs", vec!["list"]), >> + ("arcstat", vec![]), >> + ] >> +} >> + >> +// (description, function()) >> +type FunctionMapping = (&'static str, fn() -> String); >> + >> +fn function_calls() -> Vec<FunctionMapping> { >> + vec![("System Load & Uptime", get_top_processes)] >> +} > > a little confused why this gets its own category. `top` usually appears > more toward the top of our reports, this puts it on the very bottom. > also `get_top_processes` essentially also just calls a command, so not > sure why this is separated out. > This was just taken as-is from PBS, see [1]. I think it's called as a function rather than a command because we limit the output to the first 30 lines? [1] https://git.proxmox.com/?p=proxmox-backup.git;a=blob;f=src/server/report.rs;h=546555fb97ba65ae8a748e64aaf5869b6fc7dd2c;hb=HEAD#l99 >> + >> +fn get_file_content(file: impl AsRef<Path>) -> String { >> + use proxmox_sys::fs::file_read_optional_string; >> + let content = match file_read_optional_string(&file) { >> + Ok(Some(content)) => content, >> + Ok(None) => String::from("# file does not exist"), >> + Err(err) => err.to_string(), >> + }; >> + let file_name = file.as_ref().display(); >> + format!("`$ cat '{file_name}'`\n```\n{}\n```", content.trim_end()) >> +} >> + >> +fn get_directory_content(path: impl AsRef<Path>) -> String { >> + let read_dir_iter = match std::fs::read_dir(&path) { >> + Ok(iter) => iter, >> + Err(err) => { >> + return format!( >> + "`$ cat '{}*'`\n```\n# read dir failed - {err}\n```", >> + path.as_ref().display(), >> + ); >> + } >> + }; >> + let mut out = String::new(); >> + let mut first = true; >> + for entry in read_dir_iter { >> + let entry = match entry { >> + Ok(entry) => entry, >> + Err(err) => { >> + let _ = writeln!(out, "error during read-dir - {err}"); >> + continue; >> + } >> + }; >> + let path = entry.path(); >> + if path.is_file() { >> + if first { >> + let _ = writeln!(out, "{}", get_file_content(path)); >> + first = false; >> + } else { >> + let _ = writeln!(out, "\n{}", get_file_content(path)); >> + } >> + } else { >> + let _ = writeln!(out, "skipping sub-directory `{}`", path.display()); >> + } >> + } >> + out >> +} >> + >> +fn get_command_output(exe: &str, args: &Vec<&str>) -> String { >> + let output = Command::new(exe) >> + .env("PROXMOX_OUTPUT_NO_BORDER", "1") >> + .args(args) >> + .output(); >> + let output = match output { >> + Ok(output) => { >> + let mut out = String::from_utf8_lossy(&output.stdout) >> + .trim_end() >> + .to_string(); >> + let stderr = String::from_utf8_lossy(&output.stderr) >> + .trim_end() >> + .to_string(); >> + if !stderr.is_empty() { >> + let _ = writeln!(out, "\n```\nSTDERR:\n```\n{stderr}"); >> + } >> + out >> + } >> + Err(err) => err.to_string(), >> + }; >> + format!("$ `{exe} {}`\n```\n{output}\n```", args.join(" ")) >> +} >> + >> +pub fn generate_report() -> String { >> + let file_contents = files() >> + .iter() >> + .map(|group| { >> + let (group, files) = group; >> + let group_content = files >> + .iter() >> + .map(|file_name| { >> + let path = Path::new(file_name); >> + if path.is_dir() { >> + get_directory_content(path) >> + } else { >> + get_file_content(file_name) >> + } >> + }) >> + .collect::<Vec<String>>() >> + .join("\n\n"); >> + >> + format!("### {group}\n\n{group_content}") >> + }) >> + .collect::<Vec<String>>() >> + .join("\n\n"); >> + >> + let command_outputs = commands() >> + .iter() >> + .map(|(command, args)| get_command_output(command, args)) >> + .collect::<Vec<String>>() >> + .join("\n\n"); >> + >> + let function_outputs = function_calls() >> + .iter() >> + .map(|(desc, function)| { >> + let output = function(); >> + format!("#### {desc}\n{}\n", output.trim_end()) >> + }) >> + .collect::<Vec<String>>() >> + .join("\n\n"); >> + >> + format!( >> + "## FILES\n\n{file_contents}\n## COMMANDS\n\n{command_outputs}\n## FUNCTIONS\n\n{function_outputs}\n" >> + ) >> +} _______________________________________________ pdm-devel mailing list pdm-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel ^ permalink raw reply [flat|nested] 11+ messages in thread
* [pdm-devel] [PATCH datacenter-manager 2/4] api: add system report API 2025-12-01 12:58 [pdm-devel] [PATCH datacenter-manager 0/4] system report via admin cli or API Lukas Wagner 2025-12-01 12:58 ` [pdm-devel] [PATCH datacenter-manager 1/4] server: add system report implementation Lukas Wagner @ 2025-12-01 12:58 ` Lukas Wagner 2025-12-01 12:58 ` [pdm-devel] [PATCH datacenter-manager 3/4] cli: admin: add 'report' command to generate a system report Lukas Wagner ` (4 subsequent siblings) 6 siblings, 0 replies; 11+ messages in thread From: Lukas Wagner @ 2025-12-01 12:58 UTC (permalink / raw) To: pdm-devel Adds a new API endpoint under /nodes/localhost/report which returns the system report. To access it, the user/token needs Sys.Audit on /system/status, same as in PBS. Signed-off-by: Lukas Wagner <l.wagner@proxmox.com> --- server/src/api/nodes/mod.rs | 2 ++ server/src/api/nodes/report.rs | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 server/src/api/nodes/report.rs diff --git a/server/src/api/nodes/mod.rs b/server/src/api/nodes/mod.rs index a0fe14ab..d6dadb80 100644 --- a/server/src/api/nodes/mod.rs +++ b/server/src/api/nodes/mod.rs @@ -9,6 +9,7 @@ pub mod config; pub mod dns; pub mod journal; pub mod network; +pub mod report; pub mod rrddata; pub mod status; pub mod syslog; @@ -44,6 +45,7 @@ pub const SUBDIRS: SubdirMap = &sorted!([ ("dns", &dns::ROUTER), ("journal", &journal::ROUTER), ("network", &network::ROUTER), + ("report", &report::ROUTER), ("rrdata", &rrddata::ROUTER), ("status", &status::ROUTER), ("syslog", &syslog::ROUTER), diff --git a/server/src/api/nodes/report.rs b/server/src/api/nodes/report.rs new file mode 100644 index 00000000..f8c41000 --- /dev/null +++ b/server/src/api/nodes/report.rs @@ -0,0 +1,32 @@ +use anyhow::Error; + +use proxmox_router::{Permission, Router}; +use proxmox_schema::api; + +use pdm_api_types::{NODE_SCHEMA, PRIV_SYS_AUDIT}; + +use crate::report; + +#[api( + protected: true, + input: { + properties: { + node: { + schema: NODE_SCHEMA, + }, + }, + }, + returns: { + type: String, + description: "The system report for this PDM node.", + }, + access: { + permission: &Permission::Privilege(&["system", "status"], PRIV_SYS_AUDIT, false), + } +)] +/// Get the system report for this node. +pub fn generate_system_report() -> Result<String, Error> { + Ok(report::generate_report()) +} + +pub const ROUTER: Router = Router::new().get(&API_METHOD_GENERATE_SYSTEM_REPORT); -- 2.47.3 _______________________________________________ pdm-devel mailing list pdm-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel ^ permalink raw reply [flat|nested] 11+ messages in thread
* [pdm-devel] [PATCH datacenter-manager 3/4] cli: admin: add 'report' command to generate a system report 2025-12-01 12:58 [pdm-devel] [PATCH datacenter-manager 0/4] system report via admin cli or API Lukas Wagner 2025-12-01 12:58 ` [pdm-devel] [PATCH datacenter-manager 1/4] server: add system report implementation Lukas Wagner 2025-12-01 12:58 ` [pdm-devel] [PATCH datacenter-manager 2/4] api: add system report API Lukas Wagner @ 2025-12-01 12:58 ` Lukas Wagner 2025-12-01 12:58 ` [pdm-devel] [PATCH datacenter-manager 4/4] pdm-client: add bindings for system report generation Lukas Wagner ` (3 subsequent siblings) 6 siblings, 0 replies; 11+ messages in thread From: Lukas Wagner @ 2025-12-01 12:58 UTC (permalink / raw) To: pdm-devel This adds the 'proxmox-datacenter-manager-admin report' command, which prints the system report to the console. Signed-off-by: Lukas Wagner <l.wagner@proxmox.com> --- cli/admin/src/main.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/cli/admin/src/main.rs b/cli/admin/src/main.rs index 19d387f8..e6a74df2 100644 --- a/cli/admin/src/main.rs +++ b/cli/admin/src/main.rs @@ -32,6 +32,10 @@ fn main() { let cmd_def = CliCommandMap::new() .insert("remote", remotes::cli()) + .insert( + "report", + CliCommand::new(&API_METHOD_GENERATE_SYSTEM_REPORT), + ) .insert("versions", CliCommand::new(&API_METHOD_GET_VERSIONS)); let mut rpcenv = CliEnvironment::new(); @@ -83,3 +87,12 @@ async fn get_versions(verbose: bool, param: Value) -> Result<Value, anyhow::Erro Ok(Value::Null) } + +#[api] +/// Generate the system report. +async fn generate_system_report() -> Result<(), anyhow::Error> { + let report = server::api::nodes::report::generate_system_report()?; + print!("{report}"); + + Ok(()) +} -- 2.47.3 _______________________________________________ pdm-devel mailing list pdm-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel ^ permalink raw reply [flat|nested] 11+ messages in thread
* [pdm-devel] [PATCH datacenter-manager 4/4] pdm-client: add bindings for system report generation 2025-12-01 12:58 [pdm-devel] [PATCH datacenter-manager 0/4] system report via admin cli or API Lukas Wagner ` (2 preceding siblings ...) 2025-12-01 12:58 ` [pdm-devel] [PATCH datacenter-manager 3/4] cli: admin: add 'report' command to generate a system report Lukas Wagner @ 2025-12-01 12:58 ` Lukas Wagner 2025-12-01 14:55 ` [pdm-devel] [PATCH datacenter-manager 0/4] system report via admin cli or API Shannon Sterz ` (2 subsequent siblings) 6 siblings, 0 replies; 11+ messages in thread From: Lukas Wagner @ 2025-12-01 12:58 UTC (permalink / raw) To: pdm-devel This adds bindings for the `/nodes/localhost/report` endpoint which returns a system report. Signed-off-by: Lukas Wagner <l.wagner@proxmox.com> --- lib/pdm-client/src/lib.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/pdm-client/src/lib.rs b/lib/pdm-client/src/lib.rs index ddca3958..db92c1ef 100644 --- a/lib/pdm-client/src/lib.rs +++ b/lib/pdm-client/src/lib.rs @@ -1313,6 +1313,16 @@ impl<T: HttpApiClient> PdmClient<T> { .expect_json()? .data) } + + /// Get remote update summary. + pub async fn generate_system_report(&self) -> Result<String, Error> { + Ok(self + .0 + .get("/api2/extjs/nodes/localhost/report") + .await? + .expect_json()? + .data) + } } /// Builder for migration parameters. -- 2.47.3 _______________________________________________ pdm-devel mailing list pdm-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [pdm-devel] [PATCH datacenter-manager 0/4] system report via admin cli or API 2025-12-01 12:58 [pdm-devel] [PATCH datacenter-manager 0/4] system report via admin cli or API Lukas Wagner ` (3 preceding siblings ...) 2025-12-01 12:58 ` [pdm-devel] [PATCH datacenter-manager 4/4] pdm-client: add bindings for system report generation Lukas Wagner @ 2025-12-01 14:55 ` Shannon Sterz 2025-12-01 15:05 ` Stefan Hanreich 2025-12-01 15:34 ` [pdm-devel] superseded: " Lukas Wagner 6 siblings, 0 replies; 11+ messages in thread From: Shannon Sterz @ 2025-12-01 14:55 UTC (permalink / raw) To: Lukas Wagner; +Cc: Proxmox Datacenter Manager development discussion On Mon Dec 1, 2025 at 1:58 PM CET, Lukas Wagner wrote: > Still missing the UI integration. > > Lukas Wagner (4): > server: add system report implementation > api: add system report API > cli: admin: add 'report' command to generate a system report > pdm-client: add bindings for system report generation > > cli/admin/src/main.rs | 13 +++ > lib/pdm-client/src/lib.rs | 10 ++ > server/src/api/nodes/mod.rs | 2 + > server/src/api/nodes/report.rs | 32 ++++++ > server/src/lib.rs | 1 + > server/src/report.rs | 195 +++++++++++++++++++++++++++++++++ > 6 files changed, 253 insertions(+) > create mode 100644 server/src/api/nodes/report.rs > create mode 100644 server/src/report.rs gave this a quick spin and looked through the code. as you mentioned in one of the code comments at least parts of this should live in proxmox-rs and share their implementation with proxmox-backup. however, that shouldn't hold this up for now and can be done as a follow up. left two minor comments on the first patch. also tested this by building the manager binary and using it in my test container. it worked as expected (some commands failed to this being a testing container). so consider this: Reviewed-by: Shannon Sterz <s.sterz@proxmox.com> Tested-by: Shannon Sterz <s.sterz@proxmox.com> _______________________________________________ pdm-devel mailing list pdm-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [pdm-devel] [PATCH datacenter-manager 0/4] system report via admin cli or API 2025-12-01 12:58 [pdm-devel] [PATCH datacenter-manager 0/4] system report via admin cli or API Lukas Wagner ` (4 preceding siblings ...) 2025-12-01 14:55 ` [pdm-devel] [PATCH datacenter-manager 0/4] system report via admin cli or API Shannon Sterz @ 2025-12-01 15:05 ` Stefan Hanreich 2025-12-01 15:18 ` Lukas Wagner 2025-12-01 15:34 ` [pdm-devel] superseded: " Lukas Wagner 6 siblings, 1 reply; 11+ messages in thread From: Stefan Hanreich @ 2025-12-01 15:05 UTC (permalink / raw) To: Proxmox Datacenter Manager development discussion, Lukas Wagner Tested this on my machine, works fine! * used CLI to generate a report * used API to obtain a report Some thoughts on the report itself: * Add some more networking info? (potential personal bias) $ ip -details -statistics address $ ip -details -4 route show $ ip -details -6 route show Might be interesting to include them as well, some people might use e.g. wireguard or some other VPN solutions to connect to their PVE instances and those most likely won't show up just in the `/etc/network/interfaces`. Particularly when troubleshooting issues with connectivity to PVE routing information could be vital. * df command in PVE includes -T flag as well (shows type of mount) * order-wise I think it would be better to run the 'commands' section first (particular because of date and version info). Barring any additions, consider this: Tested-by: Stefan Hanreich <s.hanreich@proxmox.com> On 12/1/25 1:58 PM, Lukas Wagner wrote: > Still missing the UI integration. > > Lukas Wagner (4): > server: add system report implementation > api: add system report API > cli: admin: add 'report' command to generate a system report > pdm-client: add bindings for system report generation > > cli/admin/src/main.rs | 13 +++ > lib/pdm-client/src/lib.rs | 10 ++ > server/src/api/nodes/mod.rs | 2 + > server/src/api/nodes/report.rs | 32 ++++++ > server/src/lib.rs | 1 + > server/src/report.rs | 195 +++++++++++++++++++++++++++++++++ > 6 files changed, 253 insertions(+) > create mode 100644 server/src/api/nodes/report.rs > create mode 100644 server/src/report.rs > _______________________________________________ pdm-devel mailing list pdm-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [pdm-devel] [PATCH datacenter-manager 0/4] system report via admin cli or API 2025-12-01 15:05 ` Stefan Hanreich @ 2025-12-01 15:18 ` Lukas Wagner 0 siblings, 0 replies; 11+ messages in thread From: Lukas Wagner @ 2025-12-01 15:18 UTC (permalink / raw) To: Stefan Hanreich, Proxmox Datacenter Manager development discussion, Lukas Wagner On Mon Dec 1, 2025 at 4:05 PM CET, Stefan Hanreich wrote: > Tested this on my machine, works fine! > * used CLI to generate a report > * used API to obtain a report > > > Some thoughts on the report itself: > > * Add some more networking info? (potential personal bias) > > $ ip -details -statistics address > $ ip -details -4 route show > $ ip -details -6 route show > > Might be interesting to include them as well, some people might use e.g. > wireguard or some other VPN solutions to connect to their PVE instances > and those most likely won't show up just in the > `/etc/network/interfaces`. Particularly when troubleshooting issues with > connectivity to PVE routing information could be vital. > > * df command in PVE includes -T flag as well (shows type of mount) > > * order-wise I think it would be better to run the 'commands' section > first (particular because of date and version info). > > > Barring any additions, consider this: > Tested-by: Stefan Hanreich <s.hanreich@proxmox.com> > Ack, I'll add these commands and then change the order; v2 incoming. Thanks! _______________________________________________ pdm-devel mailing list pdm-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel ^ permalink raw reply [flat|nested] 11+ messages in thread
* [pdm-devel] superseded: [PATCH datacenter-manager 0/4] system report via admin cli or API 2025-12-01 12:58 [pdm-devel] [PATCH datacenter-manager 0/4] system report via admin cli or API Lukas Wagner ` (5 preceding siblings ...) 2025-12-01 15:05 ` Stefan Hanreich @ 2025-12-01 15:34 ` Lukas Wagner 6 siblings, 0 replies; 11+ messages in thread From: Lukas Wagner @ 2025-12-01 15:34 UTC (permalink / raw) To: Proxmox Datacenter Manager development discussion On Mon Dec 1, 2025 at 1:58 PM CET, Lukas Wagner wrote: > Still missing the UI integration. > > Lukas Wagner (4): > server: add system report implementation > api: add system report API > cli: admin: add 'report' command to generate a system report > pdm-client: add bindings for system report generation > > cli/admin/src/main.rs | 13 +++ > lib/pdm-client/src/lib.rs | 10 ++ > server/src/api/nodes/mod.rs | 2 + > server/src/api/nodes/report.rs | 32 ++++++ > server/src/lib.rs | 1 + > server/src/report.rs | 195 +++++++++++++++++++++++++++++++++ > 6 files changed, 253 insertions(+) > create mode 100644 server/src/api/nodes/report.rs > create mode 100644 server/src/report.rs superseded by v2: https://lore.proxmox.com/all/20251201153229.347742-1-l.wagner@proxmox.com/T/#t _______________________________________________ pdm-devel mailing list pdm-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel ^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2025-12-01 15:34 UTC | newest] Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2025-12-01 12:58 [pdm-devel] [PATCH datacenter-manager 0/4] system report via admin cli or API Lukas Wagner 2025-12-01 12:58 ` [pdm-devel] [PATCH datacenter-manager 1/4] server: add system report implementation Lukas Wagner 2025-12-01 14:55 ` Shannon Sterz 2025-12-01 15:06 ` Lukas Wagner 2025-12-01 12:58 ` [pdm-devel] [PATCH datacenter-manager 2/4] api: add system report API Lukas Wagner 2025-12-01 12:58 ` [pdm-devel] [PATCH datacenter-manager 3/4] cli: admin: add 'report' command to generate a system report Lukas Wagner 2025-12-01 12:58 ` [pdm-devel] [PATCH datacenter-manager 4/4] pdm-client: add bindings for system report generation Lukas Wagner 2025-12-01 14:55 ` [pdm-devel] [PATCH datacenter-manager 0/4] system report via admin cli or API Shannon Sterz 2025-12-01 15:05 ` Stefan Hanreich 2025-12-01 15:18 ` Lukas Wagner 2025-12-01 15:34 ` [pdm-devel] superseded: " Lukas Wagner
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.