Generiert aus den ansible-daten einen Netzwerkgraphen.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
doku2dot/src/main.rs

150 lines
4.4 KiB

#[macro_use]
extern crate serde_derive;
extern crate serde_yaml;
use std::path::Path;
mod parsing;
fn main() {
//read the files
//let paths = [Path::new("test.yml")];
let filenames: Vec<_> = std::env::args_os().skip(1).collect();
let hosts: Vec<Host> = filenames.iter()
.map(Path::new)
.map(|path| Host::from_file(&path))
.collect();
//build dot-graph
let nodes = hosts.iter().map(Host::to_dot_node);
let edges = hosts.iter().flat_map(Host::to_dot_edge);
//render it
println!("graph antennen {{");
for node in nodes {
println!("{}", node);
}
for edge in edges {
println!("{}", edge);
}
println!("}}");
}
#[derive(Debug)]
pub struct Host {
name: String,
ip: String,
parent: String,
kind: HostKind,
}
impl Host {
fn from_file(path: &Path) -> Self {
let (host, hostname) = parsing::RawHost::from_file(path);
host.parse(hostname)
}
fn to_dot_node(&self) -> String {
let mut attributes = vec!
[ "shape=record".to_string()
, "style=filled".into()
];
let record;
// type-specific handling
use HostKind::*;
match self.kind {
Client {coordinates, ref subnet, ref mac, .. } =>
{ attributes.push("fillcolor=lightgray".into())
; if let Some(coordinates) = coordinates
{ attributes.push(format!("pos=\"{breitengrad},{längengrad}\""
, längengrad=coordinates[0], breitengrad=coordinates[1]))
}
; record =
( self.name.clone()
, (self.kind.name(), mac.clone())
, (self.ip.clone(), subnet.clone())
, ("no ipv6", "no 6-subnet")
).recordify()
},
AccessPoint { ref mac, .. } => record =
( self.name.clone()
, (self.kind.name(), mac.clone() )
, self.ip.clone()
).recordify(),
_ => record = (self.name.clone(), self.kind.name(), self.ip.clone()).recordify(),
};
attributes.push(format!("label=\"{}\"", record));
let attributes = attributes.join(", ");
format!("\"{name}\" [{attributes}]", name=self.name, attributes=attributes)
}
fn to_dot_edge(&self) -> Option<String> {
match self.kind {
HostKind::Client { ref ssid, .. } =>
format!("\"{name}\" -- \"{parent}\" [label=\"{ssid}\"]", name=self.name, parent=self.parent, ssid=ssid).into(),
// hier eventuelle ausnahmen für bestimmte typen die keine parents haben eintragen
// mainly template und sol
_ =>
format!("\"{name}\" -- \"{parent}\"", name=self.name, parent=self.parent).into(),
}
}
}
#[derive(Debug)]
enum HostKind {
Client { mac: String, subnet: String, coordinates: Option<[f64;2]>, ssid: String },
AccessPoint { mac: String, ssid: String },
Service,
Other,
}
impl HostKind {
fn name(&self) -> &'static str {
use HostKind::*;
match *self {
Client { .. } => "Client",
AccessPoint { .. } => "AccessPoint",
Service => "Service",
Other => "Other",
}
}
}
/** dieser Trait ermöglicht es verschachtelte tupel in ein label für einen record-shaped-node für
dotfiles umzuwandeln. inputwerte werden nicht escaped
assert_eq!(
("a", ("b", "c", "d"), ("e","f"), "g").recordify(),
"{a|{b|c|d}|{e|f}|g}".into())
*/
pub trait DotRecord {
fn recordify(self) -> String;
}
impl DotRecord for String {
fn recordify(self) -> String { self }
}
impl<'a> DotRecord for &'a str {
fn recordify(self) -> String { self.into() }
}
impl<A: DotRecord, B: DotRecord> DotRecord for (A,B) {
fn recordify(self) -> String {
format!("{{{}|{}}}", self.0.recordify(), self.1.recordify())
}
}
impl<A: DotRecord, B: DotRecord, C: DotRecord> DotRecord for (A,B,C) {
fn recordify(self) -> String {
format!("{{{}|{}|{}}}", self.0.recordify(), self.1.recordify(), self.2.recordify())
}
}
impl<A: DotRecord, B: DotRecord, C: DotRecord, D: DotRecord> DotRecord for (A,B,C,D) {
fn recordify(self) -> String {
format!("{{{}|{}|{}|{}}}", self.0.recordify(), self.1.recordify(), self.2.recordify(), self.3.recordify())
}
}
impl<A: DotRecord, B: DotRecord, C: DotRecord, D: DotRecord, E: DotRecord> DotRecord for (A,B,C,D,E) {
fn recordify(self) -> String {
format!("{{{}|{}|{}|{}|{}}}", self.0.recordify(), self.1.recordify(), self.2.recordify(), self.3.recordify(), self.4.recordify())
}
}