split of disk module

This commit is contained in:
Robin Appelman 2023-05-02 21:24:52 +02:00
commit 89375a13bb
6 changed files with 117 additions and 109 deletions

26
flake.lock generated
View file

@ -5,11 +5,11 @@
"nixpkgs": "nixpkgs" "nixpkgs": "nixpkgs"
}, },
"locked": { "locked": {
"lastModified": 1659610603, "lastModified": 1671096816,
"narHash": "sha256-LYgASYSPYo7O71WfeUOaEUzYfzuXm8c8eavJcel+pfI=", "narHash": "sha256-ezQCsNgmpUHdZANDCILm3RvtO1xH8uujk/+EqNvzIOg=",
"owner": "nix-community", "owner": "nix-community",
"repo": "naersk", "repo": "naersk",
"rev": "c6a45e4277fa58abd524681466d3450f896dc094", "rev": "d998160d6a076cfe8f9741e56aeec7e267e3e114",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -20,9 +20,10 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 0, "lastModified": 1674407282,
"narHash": "sha256-ogcrJszrCg23/mIcLEOUCMKgdWlqMJ4QqezvX0V2ZQk=", "narHash": "sha256-2qwc8mrPINSFdWffPK+ji6nQ9aGnnZyHSItVcYDZDlk=",
"path": "/nix/store/f6y01zll9swq7rvf82ya4r3hjs9j93py-source", "path": "/nix/store/47v7isgz6w8zgb1224d46lwvwkdd69bm-source",
"rev": "ab1254087f4cdf4af74b552d7fc95175d9bdbb49",
"type": "path" "type": "path"
}, },
"original": { "original": {
@ -32,9 +33,10 @@
}, },
"nixpkgs_2": { "nixpkgs_2": {
"locked": { "locked": {
"lastModified": 0, "lastModified": 1674407282,
"narHash": "sha256-ogcrJszrCg23/mIcLEOUCMKgdWlqMJ4QqezvX0V2ZQk=", "narHash": "sha256-2qwc8mrPINSFdWffPK+ji6nQ9aGnnZyHSItVcYDZDlk=",
"path": "/nix/store/f6y01zll9swq7rvf82ya4r3hjs9j93py-source", "path": "/nix/store/47v7isgz6w8zgb1224d46lwvwkdd69bm-source",
"rev": "ab1254087f4cdf4af74b552d7fc95175d9bdbb49",
"type": "path" "type": "path"
}, },
"original": { "original": {
@ -51,11 +53,11 @@
}, },
"utils": { "utils": {
"locked": { "locked": {
"lastModified": 1659877975, "lastModified": 1667395993,
"narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=", "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
"owner": "numtide", "owner": "numtide",
"repo": "flake-utils", "repo": "flake-utils",
"rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0", "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f",
"type": "github" "type": "github"
}, },
"original": { "original": {

95
src/disk/mod.rs Normal file
View file

@ -0,0 +1,95 @@
use ahash::{AHashSet, AHasher};
use color_eyre::{Report, Result};
use once_cell::sync::Lazy;
use regex::Regex;
use std::ffi::CString;
use std::fs::File;
use std::hash::{Hash, Hasher};
use std::io::{BufRead, BufReader};
use std::mem::MaybeUninit;
pub mod zfs;
#[derive(Debug, Clone, Default)]
pub struct IoStats {
pub interface: String,
pub bytes_sent: u64,
pub bytes_received: u64,
}
#[derive(Clone, Debug)]
pub struct DiskUsage {
pub name: String,
pub size: u64,
pub free: u64,
}
pub fn disk_stats() -> Result<impl Iterator<Item = IoStats>> {
static DISK_REGEX: Lazy<Regex> =
Lazy::new(|| Regex::new(r" ([sv]d[a-z]+|nvme[0-9]n[0-9]|mmcblk[0-9]) ").unwrap());
let stat = BufReader::new(File::open("/proc/diskstats")?);
Ok(stat
.lines()
.filter_map(Result::ok)
.filter(|line| DISK_REGEX.is_match(line))
.filter_map(|line: String| {
let mut parts = line.split_whitespace().skip(2);
let name: String = parts.next()?.into();
let _read_count = parts.next();
let _read_merged_count = parts.next();
let read_sectors = parts.next()?.parse::<u64>().ok()?;
let mut parts = parts.skip(1);
let _write_count = parts.next();
let _write_merged_count = parts.next();
let write_sectors = parts.next()?.parse::<u64>().ok()?;
Some(IoStats {
interface: name,
bytes_sent: write_sectors * 512,
bytes_received: read_sectors * 512,
})
}))
}
pub fn disk_usage() -> Result<impl Iterator<Item = DiskUsage>> {
let stat = BufReader::new(File::open("/proc/mounts")?);
let mut found_disks = AHashSet::with_capacity(8);
Ok(stat
.lines()
.filter_map(Result::ok)
.filter(|line| line.starts_with('/'))
.filter(|line| !line.contains("/dev/loop"))
.filter_map(move |line: String| {
let mut parts = line.split_ascii_whitespace();
let disk = parts.next()?;
if !found_disks.insert(hash_str(disk)) {
return None;
}
let mount_point = parts.next()?;
let stat = statvfs(&mount_point).ok()?;
Some(DiskUsage {
name: mount_point.to_string(),
size: stat.f_blocks * stat.f_frsize as u64,
free: stat.f_bavail * stat.f_frsize as u64,
})
}))
}
fn statvfs(path: &str) -> Result<libc::statvfs> {
let path = CString::new(path)?;
let mut vfs = MaybeUninit::<libc::statvfs>::uninit();
let result = unsafe { libc::statvfs(path.as_ptr(), vfs.as_mut_ptr()) };
if result == 0 {
let vfs = unsafe { vfs.assume_init() };
Ok(vfs)
} else {
Err(Report::msg("Failed to stat vfs"))
}
}
fn hash_str(s: &str) -> u64 {
let mut hasher = AHasher::default();
s.hash(&mut hasher);
hasher.finish()
}

View file

@ -1,4 +1,4 @@
use crate::sensors::DiskUsage; use crate::disk::DiskUsage;
use color_eyre::Result; use color_eyre::Result;
use std::fmt::Write; use std::fmt::Write;
use std::fs::read_to_string; use std::fs::read_to_string;

View file

@ -1,12 +1,13 @@
pub mod disk;
pub mod docker; pub mod docker;
pub mod nvidia; pub mod nvidia;
pub mod power; pub mod power;
pub mod sensors; pub mod sensors;
pub mod zfs;
use crate::sensors::temperatures; use crate::disk::disk_usage;
use crate::disk::zfs::pools;
use crate::disk::*;
use crate::sensors::*; use crate::sensors::*;
use crate::zfs::pools;
use color_eyre::Result; use color_eyre::Result;
use std::fmt::Write; use std::fmt::Write;

View file

@ -3,15 +3,15 @@ use color_eyre::{Report, Result};
use futures_util::pin_mut; use futures_util::pin_mut;
use futures_util::StreamExt; use futures_util::StreamExt;
use libmdns::Responder; use libmdns::Responder;
use palantir::disk::zfs::arcstats;
use palantir::docker::{get_docker, stat, Container}; use palantir::docker::{get_docker, stat, Container};
use palantir::get_metrics; use palantir::get_metrics;
use palantir::power::power_usage; use palantir::power::power_usage;
use palantir::zfs::arcstats;
use std::time::Duration; use std::time::Duration;
use tokio::runtime::Handle; use tokio::runtime::Handle;
use tokio::spawn; use tokio::spawn;
use tokio::time::sleep; use tokio::time::sleep;
use tracing::{info, warn}; use tracing::warn;
use warp::reject::Reject; use warp::reject::Reject;
use warp::{Filter, Rejection}; use warp::{Filter, Rejection};

View file

@ -1,14 +1,8 @@
use ahash::{AHasher, RandomState}; use crate::disk::IoStats;
use color_eyre::{Report, Result}; use color_eyre::{Report, Result};
use once_cell::sync::Lazy;
use regex::Regex;
use std::array::IntoIter; use std::array::IntoIter;
use std::collections::HashSet;
use std::ffi::{CStr, CString};
use std::fs::{read, read_dir, read_to_string, File}; use std::fs::{read, read_dir, read_to_string, File};
use std::hash::{Hash, Hasher};
use std::io::{BufRead, BufReader}; use std::io::{BufRead, BufReader};
use std::mem::MaybeUninit;
use std::os::unix::ffi::OsStrExt; use std::os::unix::ffi::OsStrExt;
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
@ -33,20 +27,6 @@ pub struct Memory {
pub available: u64, pub available: u64,
} }
#[derive(Debug, Clone, Default)]
pub struct IoStats {
pub interface: String,
pub bytes_sent: u64,
pub bytes_received: u64,
}
#[derive(Clone, Debug)]
pub struct DiskUsage {
pub name: String,
pub size: u64,
pub free: u64,
}
pub fn temperatures() -> Result<Temperatures> { pub fn temperatures() -> Result<Temperatures> {
let mut temps = Temperatures::default(); let mut temps = Temperatures::default();
@ -209,58 +189,6 @@ pub fn hostname() -> Result<String> {
.map_err(|_| Report::msg("non utf8 hostname")) .map_err(|_| Report::msg("non utf8 hostname"))
} }
pub fn disk_stats() -> Result<impl Iterator<Item = IoStats>> {
static DISK_REGEX: Lazy<Regex> =
Lazy::new(|| Regex::new(r" ([sv]d[a-z]+|nvme[0-9]n[0-9]|mmcblk[0-9]) ").unwrap());
let stat = BufReader::new(File::open("/proc/diskstats")?);
Ok(stat
.lines()
.filter_map(Result::ok)
.filter(|line| DISK_REGEX.is_match(line))
.filter_map(|line: String| {
let mut parts = line.split_whitespace().skip(2);
let name: String = parts.next()?.into();
let _read_count = parts.next();
let _read_merged_count = parts.next();
let read_sectors = parts.next()?.parse::<u64>().ok()?;
let mut parts = parts.skip(1);
let _write_count = parts.next();
let _write_merged_count = parts.next();
let write_sectors = parts.next()?.parse::<u64>().ok()?;
Some(IoStats {
interface: name,
bytes_sent: write_sectors * 512,
bytes_received: read_sectors * 512,
})
}))
}
pub fn disk_usage() -> Result<impl Iterator<Item = DiskUsage>> {
let stat = BufReader::new(File::open("/proc/mounts")?);
let mut found_disks = HashSet::with_capacity_and_hasher(8, RandomState::new());
Ok(stat
.lines()
.filter_map(Result::ok)
.filter(|line| line.starts_with('/'))
.filter(|line| !line.contains("/dev/loop"))
.filter_map(move |line: String| {
let mut parts = line.split_ascii_whitespace();
let disk = parts.next()?;
if !found_disks.insert(hash_str(disk)) {
return None;
}
let mount_point = parts.next()?;
let mount_point = CString::new(mount_point).ok()?;
let stat = statvfs(&mount_point).ok()?;
Some(DiskUsage {
name: mount_point.into_string().unwrap(),
size: stat.f_blocks * stat.f_frsize as u64,
free: stat.f_bavail * stat.f_frsize as u64,
})
}))
}
pub fn clock_ticks() -> Result<u64> { pub fn clock_ticks() -> Result<u64> {
let result = unsafe { libc::sysconf(libc::_SC_CLK_TCK) }; let result = unsafe { libc::sysconf(libc::_SC_CLK_TCK) };
@ -271,18 +199,6 @@ pub fn clock_ticks() -> Result<u64> {
} }
} }
fn statvfs(path: &CStr) -> Result<libc::statvfs> {
let mut vfs = MaybeUninit::<libc::statvfs>::uninit();
let result = unsafe { libc::statvfs(path.as_ptr(), vfs.as_mut_ptr()) };
if result == 0 {
let vfs = unsafe { vfs.assume_init() };
Ok(vfs)
} else {
Err(Report::msg("Failed to stat vfs"))
}
}
fn cpu_count() -> Result<u64> { fn cpu_count() -> Result<u64> {
let result = unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) }; let result = unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) };
@ -292,9 +208,3 @@ fn cpu_count() -> Result<u64> {
Ok(result as u64) Ok(result as u64)
} }
} }
fn hash_str(s: &str) -> u64 {
let mut hasher = AHasher::default();
s.hash(&mut hasher);
hasher.finish()
}