Skip to content

Commit 0e4d1a3

Browse files
authored
Merge pull request #9 from stackabletech/productionize
Initial productionization
2 parents 4afe36c + 8999b15 commit 0e4d1a3

File tree

11 files changed

+2707
-336
lines changed

11 files changed

+2707
-336
lines changed

Cargo.lock

Lines changed: 2284 additions & 130 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,16 @@ version = "0.1.0"
44
edition = "2021"
55

66
[dependencies]
7+
clap = { version = "4.5.20", features = ["derive"] }
78

89
hickory-resolver = "0.24.1"
910
local-ip-address = "0.6.3"
1011
serde = { version = "1.0.210", features = ["derive"] }
1112
serde_json = "1.0.128"
13+
stackable-operator = { git = "https://github.com/stackabletech/operator-rs", version = "0.81.0" }
1214
sysinfo = "0.32.0"
15+
tracing = "0.1.40"
1316
users = "0.11.0"
17+
18+
[build-dependencies]
19+
built = { version = "0.7", features = ["chrono", "git2"] }

build.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
fn main() {
2+
built::write_built_file().unwrap();
3+
}

src/main.rs

Lines changed: 61 additions & 145 deletions
Original file line numberDiff line numberDiff line change
@@ -1,158 +1,74 @@
11
mod system_information;
22

3-
use local_ip_address::list_afinet_netifas;
4-
use std::collections::{HashMap, HashSet};
5-
use sysinfo::{Disks, System};
6-
7-
use crate::system_information::{SystemInformation, SystemNetworkInfo};
8-
use hickory_resolver::system_conf::read_system_conf;
9-
use hickory_resolver::Resolver;
10-
use std::net::IpAddr;
11-
use std::time::Duration;
12-
13-
fn main() {
14-
// Please note that we use "new_all" to ensure that all list of
15-
// components, network interfaces, disks and users are already
16-
// filled!
17-
let sys = System::new_all();
18-
19-
let disks = Disks::new_with_refreshed_list();
20-
let disks = disks
21-
.into_iter()
22-
.map(|disk| system_information::Disk::from(disk))
23-
.collect();
24-
25-
let system_network_information = get_network_info();
26-
27-
let current_uid = users::get_current_uid();
28-
let current_gid = users::get_current_gid();
29-
let current_user = users::get_user_by_uid(current_uid).unwrap();
30-
31-
32-
let system_information = SystemInformation {
33-
cpu_count: sys.cpus().len(),
34-
physical_core_count: sys.physical_core_count(),
35-
36-
total_memory: sys.total_memory(),
37-
free_memory: sys.free_memory(),
38-
available_memory: sys.available_memory(),
39-
used_memory: sys.used_memory(),
40-
41-
total_swap: sys.total_swap(),
42-
free_swap: sys.free_swap(),
43-
used_swap: sys.used_swap(),
44-
45-
total_memory_cgroup: sys.cgroup_limits().map(|limit| limit.total_memory),
46-
free_memory_cgroup: sys.cgroup_limits().map(|limit| limit.free_memory),
47-
free_swap_cgroup: sys.cgroup_limits().map(|limit| limit.free_swap),
48-
49-
system_name: System::name(),
50-
kernel_version: System::kernel_version(),
51-
os_version: System::long_os_version(),
52-
host_name: System::host_name(),
53-
cpu_arch: System::cpu_arch(),
54-
55-
disks,
56-
57-
network_information: system_network_information,
58-
59-
60-
// Adding current user, UID, and GID info
61-
current_user: current_user.name().to_str().unwrap().to_string(),
62-
current_uid,
63-
current_gid,
64-
};
65-
66-
let serialized = serde_json::to_string_pretty(&system_information).unwrap();
67-
println!("{}", serialized);
68-
69-
// TODO:
70-
// Current time
71-
// SElinux/AppArmor
72-
// Maybe env variables (may contain secrets)
73-
// dmesg/syslog?
74-
// capabilities?
75-
// downward API
76-
// Somehow get the custom resources logged?
77-
78-
// Things left out for now because it doesn't seem too useful:
79-
// - Running processes
80-
// - Uptime/boot time
81-
// - Load average
82-
// - Network utilization
83-
// - Users/Groups
3+
use clap::{crate_description, crate_version, Parser};
4+
use stackable_operator::logging::TracingTarget;
5+
use std::path::PathBuf;
6+
7+
use crate::system_information::SystemInformation;
8+
use std::time::Instant;
9+
10+
const APP_NAME: &str = "containerdebug";
11+
12+
/// Collects and prints helpful debugging information about the environment that it is running in.
13+
#[derive(clap::Parser)]
14+
struct Opts {
15+
/// Loop every DURATION, instead of shutting down once completed (default DURATION: 1m)
16+
#[clap(
17+
long = "loop",
18+
value_name = "INTERVAL",
19+
default_missing_value = "1m",
20+
num_args = 0..=1,
21+
require_equals = true,
22+
)]
23+
loop_interval: Option<stackable_operator::time::Duration>,
24+
25+
#[clap(long, short = 'o')]
26+
output: Option<PathBuf>,
27+
28+
/// Tracing log collector system
29+
#[arg(long, env, default_value_t, value_enum)]
30+
pub tracing_target: TracingTarget,
8431
}
8532

86-
fn get_network_info() -> SystemNetworkInfo {
87-
/*
88-
let resolver = Resolver::from_system_conf()
89-
.map_err(|e| e.to_string())
90-
.unwrap();
91-
*/
92-
let (resolver_config, mut resolver_opts) = read_system_conf().unwrap();
93-
resolver_opts.timeout = Duration::from_secs(5);
94-
let resolver = Resolver::new(resolver_config, resolver_opts).unwrap();
95-
96-
let interfaces = match list_afinet_netifas() {
97-
Ok(netifs) => {
98-
let mut interface_map = std::collections::HashMap::new();
99-
100-
// Iterate over the network interfaces and group them by name
101-
// An interface may appear multiple times if it has multiple IP addresses (e.g. IPv4 and IPv6)
102-
for (name, ip_addr) in netifs {
103-
interface_map
104-
.entry(name)
105-
.or_insert_with(Vec::new)
106-
.push(ip_addr);
107-
}
108-
interface_map
109-
}
110-
Err(_) => HashMap::new(),
111-
};
33+
mod built_info {
34+
include!(concat!(env!("OUT_DIR"), "/built.rs"));
35+
}
11236

113-
let mut ip_set: HashSet<IpAddr> = HashSet::new();
114-
for (_, ip_addrs) in interfaces.iter() {
115-
for ip_addr in ip_addrs {
116-
ip_set.insert(ip_addr.clone());
37+
fn main() {
38+
let opts = Opts::parse();
39+
stackable_operator::logging::initialize_logging(
40+
"CONTAINERDEBUG_LOG",
41+
APP_NAME,
42+
opts.tracing_target,
43+
);
44+
stackable_operator::utils::print_startup_string(
45+
crate_description!(),
46+
crate_version!(),
47+
built_info::GIT_VERSION,
48+
built_info::TARGET,
49+
built_info::BUILT_TIME_UTC,
50+
built_info::RUSTC_VERSION,
51+
);
52+
53+
let mut next_run = Instant::now();
54+
loop {
55+
let next_run_sleep = next_run.saturating_duration_since(Instant::now());
56+
if !next_run_sleep.is_zero() {
57+
tracing::info!(?next_run, "scheduling next run...");
11758
}
118-
}
59+
std::thread::sleep(next_run_sleep);
11960

120-
let mut reverse_lookups = HashMap::new();
121-
for ip in ip_set {
122-
if let Ok(result) = resolver.reverse_lookup(ip) {
123-
for ptr_record in result {
124-
let hostname = ptr_record.to_utf8();
125-
reverse_lookups
126-
.entry(ip)
127-
.or_insert_with(Vec::new)
128-
.push(hostname);
129-
}
130-
}
131-
}
61+
let system_information = SystemInformation::collect();
13262

133-
let mut hostname_set: HashSet<String> = HashSet::new();
134-
for (_, hostnames) in reverse_lookups.iter() {
135-
for hostname in hostnames {
136-
hostname_set.insert(hostname.clone());
63+
let serialized = serde_json::to_string_pretty(&system_information).unwrap();
64+
// println!("{serialized}");
65+
if let Some(output_path) = &opts.output {
66+
std::fs::write(output_path, &serialized).unwrap();
13767
}
138-
}
13968

140-
let mut forward_lookups = HashMap::new();
141-
for hostname in hostname_set {
142-
if let Ok(result) = resolver.lookup_ip(hostname.clone()) {
143-
for ip_addr in result {
144-
forward_lookups
145-
.entry(hostname.clone())
146-
.or_insert_with(Vec::new)
147-
.push(ip_addr);
148-
}
69+
match opts.loop_interval {
70+
Some(interval) => next_run += interval,
71+
None => break,
14972
}
15073
}
151-
152-
let system_network_information = SystemNetworkInfo {
153-
network_interfaces: interfaces,
154-
reverse_lookups,
155-
forward_lookups,
156-
};
157-
system_network_information
15874
}

src/system_information.rs

Lines changed: 0 additions & 61 deletions
This file was deleted.

src/system_information/disk.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
use serde::Serialize;
2+
3+
#[derive(Debug, Serialize)]
4+
pub struct Disk {
5+
pub name: String,
6+
pub mount_point: String,
7+
pub total_space: u64,
8+
pub available_space: u64,
9+
}
10+
11+
impl Disk {
12+
#[tracing::instrument(name = "Disk::collect_all")]
13+
pub fn collect_all() -> Vec<Self> {
14+
let disks = sysinfo::Disks::new_with_refreshed_list();
15+
if disks.into_iter().next().is_none() {
16+
tracing::info!("no disks found");
17+
}
18+
disks.into_iter().map(Self::from).collect()
19+
}
20+
}
21+
22+
impl From<&sysinfo::Disk> for Disk {
23+
fn from(sysinfo_disk: &sysinfo::Disk) -> Self {
24+
let disk = Disk {
25+
name: sysinfo_disk.name().to_string_lossy().into_owned(),
26+
mount_point: sysinfo_disk.mount_point().to_string_lossy().into_owned(),
27+
total_space: sysinfo_disk.total_space(),
28+
available_space: sysinfo_disk.available_space(),
29+
};
30+
tracing::info!(
31+
disk.mount_point,
32+
disk.name,
33+
disk.space.total = disk.total_space,
34+
disk.space.available = disk.available_space,
35+
"found disk"
36+
);
37+
disk
38+
}
39+
}

src/system_information/mod.rs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
use serde::Serialize;
2+
3+
pub mod disk;
4+
pub mod network;
5+
pub mod os;
6+
pub mod resources;
7+
pub mod user;
8+
9+
#[derive(Debug, Serialize)]
10+
pub struct SystemInformation {
11+
pub resources: resources::Resources,
12+
pub os: os::OperatingSystem,
13+
pub current_user: user::User,
14+
pub disks: Vec<disk::Disk>,
15+
pub network: network::SystemNetworkInfo,
16+
// TODO:
17+
// Current time
18+
// SElinux/AppArmor
19+
// Maybe env variables (may contain secrets)
20+
// dmesg/syslog?
21+
// capabilities?
22+
// downward API
23+
// Somehow get the custom resources logged?
24+
25+
// Things left out for now because it doesn't seem too useful:
26+
// - Running processes
27+
// - Uptime/boot time
28+
// - Load average
29+
// - Network utilization
30+
// - Users/Groups
31+
}
32+
33+
impl SystemInformation {
34+
#[tracing::instrument(name = "SystemInformation::collect")]
35+
pub fn collect() -> Self {
36+
tracing::info!("Starting data collection");
37+
let info = Self {
38+
resources: resources::Resources::collect(),
39+
os: os::OperatingSystem::collect(),
40+
current_user: user::User::collect_current(),
41+
disks: disk::Disk::collect_all(),
42+
network: network::SystemNetworkInfo::collect(),
43+
};
44+
tracing::info!("Data collection finished");
45+
info
46+
}
47+
}

0 commit comments

Comments
 (0)