mirror of
https://github.com/edera-dev/krata.git
synced 2025-08-03 05:10:55 +00:00
* chore(code): simple code cleanup * chore(code): additional code cleanup * feature(krata): rework api and make ip assignment persistent to database * rework and cleanup * fix daemon config references
165 lines
5.0 KiB
Rust
165 lines
5.0 KiB
Rust
use std::{collections::HashMap, time::Duration};
|
|
|
|
use anyhow::Result;
|
|
use fancy_duration::FancyDuration;
|
|
use human_bytes::human_bytes;
|
|
use prost_reflect::{DynamicMessage, ReflectMessage};
|
|
use prost_types::Value;
|
|
use termtree::Tree;
|
|
|
|
use krata::v1::common::{Zone, ZoneMetricFormat, ZoneMetricNode, ZoneState};
|
|
|
|
pub fn proto2dynamic(proto: impl ReflectMessage) -> Result<DynamicMessage> {
|
|
Ok(DynamicMessage::decode(
|
|
proto.descriptor(),
|
|
proto.encode_to_vec().as_slice(),
|
|
)?)
|
|
}
|
|
|
|
pub fn value2kv(value: serde_json::Value) -> Result<HashMap<String, String>> {
|
|
let mut map = HashMap::new();
|
|
fn crawl(prefix: String, map: &mut HashMap<String, String>, value: serde_json::Value) {
|
|
fn dot(prefix: &str, next: String) -> String {
|
|
if prefix.is_empty() {
|
|
next.to_string()
|
|
} else {
|
|
format!("{}.{}", prefix, next)
|
|
}
|
|
}
|
|
|
|
match value {
|
|
serde_json::Value::Null => {
|
|
map.insert(prefix, "null".to_string());
|
|
}
|
|
|
|
serde_json::Value::String(value) => {
|
|
map.insert(prefix, value);
|
|
}
|
|
|
|
serde_json::Value::Bool(value) => {
|
|
map.insert(prefix, value.to_string());
|
|
}
|
|
|
|
serde_json::Value::Number(value) => {
|
|
map.insert(prefix, value.to_string());
|
|
}
|
|
|
|
serde_json::Value::Array(value) => {
|
|
for (i, item) in value.into_iter().enumerate() {
|
|
let next = dot(&prefix, i.to_string());
|
|
crawl(next, map, item);
|
|
}
|
|
}
|
|
|
|
serde_json::Value::Object(value) => {
|
|
for (key, item) in value {
|
|
let next = dot(&prefix, key);
|
|
crawl(next, map, item);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
crawl("".to_string(), &mut map, value);
|
|
Ok(map)
|
|
}
|
|
|
|
pub fn proto2kv(proto: impl ReflectMessage) -> Result<HashMap<String, String>> {
|
|
let message = proto2dynamic(proto)?;
|
|
let value = serde_json::to_value(message)?;
|
|
value2kv(value)
|
|
}
|
|
|
|
pub fn kv2line(map: HashMap<String, String>) -> String {
|
|
map.iter()
|
|
.map(|(k, v)| format!("{}=\"{}\"", k, v.replace('"', "\\\"")))
|
|
.collect::<Vec<_>>()
|
|
.join(" ")
|
|
}
|
|
|
|
pub fn zone_state_text(status: ZoneState) -> String {
|
|
match status {
|
|
ZoneState::Creating => "creating",
|
|
ZoneState::Created => "created",
|
|
ZoneState::Destroying => "destroying",
|
|
ZoneState::Destroyed => "destroyed",
|
|
ZoneState::Exited => "exited",
|
|
ZoneState::Failed => "failed",
|
|
_ => "unknown",
|
|
}
|
|
.to_string()
|
|
}
|
|
|
|
pub fn zone_simple_line(zone: &Zone) -> String {
|
|
let state = zone_state_text(
|
|
zone.status
|
|
.as_ref()
|
|
.map(|x| x.state())
|
|
.unwrap_or(ZoneState::Unknown),
|
|
);
|
|
let name = zone.spec.as_ref().map(|x| x.name.as_str()).unwrap_or("");
|
|
let network_status = zone.status.as_ref().and_then(|x| x.network_status.as_ref());
|
|
let ipv4 = network_status.map(|x| x.zone_ipv4.as_str()).unwrap_or("");
|
|
let ipv6 = network_status.map(|x| x.zone_ipv6.as_str()).unwrap_or("");
|
|
format!("{}\t{}\t{}\t{}\t{}", zone.id, state, name, ipv4, ipv6)
|
|
}
|
|
|
|
fn metrics_value_string(value: Value) -> String {
|
|
proto2dynamic(value)
|
|
.map(|x| serde_json::to_string(&x).ok())
|
|
.ok()
|
|
.flatten()
|
|
.unwrap_or_default()
|
|
}
|
|
|
|
fn metrics_value_numeric(value: Value) -> f64 {
|
|
let string = metrics_value_string(value);
|
|
string.parse::<f64>().ok().unwrap_or(f64::NAN)
|
|
}
|
|
|
|
pub fn metrics_value_pretty(value: Value, format: ZoneMetricFormat) -> String {
|
|
match format {
|
|
ZoneMetricFormat::Bytes => human_bytes(metrics_value_numeric(value)),
|
|
ZoneMetricFormat::Integer => (metrics_value_numeric(value) as u64).to_string(),
|
|
ZoneMetricFormat::DurationSeconds => {
|
|
FancyDuration(Duration::from_secs_f64(metrics_value_numeric(value))).to_string()
|
|
}
|
|
_ => metrics_value_string(value),
|
|
}
|
|
}
|
|
|
|
fn metrics_flat_internal(prefix: &str, node: ZoneMetricNode, map: &mut HashMap<String, String>) {
|
|
if let Some(value) = node.value {
|
|
map.insert(prefix.to_string(), metrics_value_string(value));
|
|
}
|
|
|
|
for child in node.children {
|
|
let path = if prefix.is_empty() {
|
|
child.name.to_string()
|
|
} else {
|
|
format!("{}.{}", prefix, child.name)
|
|
};
|
|
metrics_flat_internal(&path, child, map);
|
|
}
|
|
}
|
|
|
|
pub fn metrics_flat(root: ZoneMetricNode) -> HashMap<String, String> {
|
|
let mut map = HashMap::new();
|
|
metrics_flat_internal("", root, &mut map);
|
|
map
|
|
}
|
|
|
|
pub fn metrics_tree(node: ZoneMetricNode) -> Tree<String> {
|
|
let mut name = node.name.to_string();
|
|
let format = node.format();
|
|
if let Some(value) = node.value {
|
|
let value_string = metrics_value_pretty(value, format);
|
|
name.push_str(&format!(": {}", value_string));
|
|
}
|
|
|
|
let mut tree = Tree::new(name);
|
|
for child in node.children {
|
|
tree.push(metrics_tree(child));
|
|
}
|
|
tree
|
|
}
|