improves workings

Signed-off-by: Jochen Maes <jochen@sejo-it.be>
This commit is contained in:
Jochen Maes 2023-10-27 07:08:18 +02:00
parent 55fc77b728
commit 71ee0aaab0
11 changed files with 168 additions and 209 deletions

44
.drone.yml Normal file
View File

@ -0,0 +1,44 @@
---
kind: pipeline
type: docker
name: "Mouse release"
platform:
arch: amd64
trigger:
event:
- tag
volumes:
- name: dockersock
host:
path: /var/run/docker.sock
- name: artifacts
temp: {}
steps:
- name: build amd64
image: rust:1.73
commands:
- rustup target add x86_64-unknown-linux-musl
- rustup target add aarch64-unknown-linux-musl
- cargo build --target x86_64-unknown-linux-musl --bins -r
- cargo build --target aarch64-unknown-linux-musl --bins -r
- cp target/x86_64-unknown-linux-musl/release/mouse /artifcats/mouse-amd64
- cp target/aarch64-unknown-linux-musl/release/mouse /artifcats/mouse-arm64
volumes:
- name: artifacts
path: /artifcats/
- name: create gitea release
image: plugins/gitea-release
settings:
api_key:
from_secret: gitea_api_key
base_url: https://gitea.sejo-it.be
checksum: sha265
files: /artifacts/*
volumes:
- name: artifacts
path: /artifcats/

20
Cargo.lock generated
View File

@ -52,9 +52,9 @@ dependencies = [
[[package]]
name = "clap"
version = "4.4.6"
version = "4.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d04704f56c2cde07f43e8e2c154b43f216dc5c92fc98ada720177362f953b956"
checksum = "ac495e00dcec98c83465d5ad66c5c4fabd652fd6686e7c6269b117e729a6f17b"
dependencies = [
"clap_builder",
"clap_derive",
@ -62,9 +62,9 @@ dependencies = [
[[package]]
name = "clap_builder"
version = "4.4.6"
version = "4.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e231faeaca65ebd1ea3c737966bf858971cd38c3849107aa3ea7de90a804e45"
checksum = "c77ed9a32a62e6ca27175d00d29d05ca32e396ea1eb5fb01d8256b669cec7663"
dependencies = [
"anstream",
"anstyle",
@ -74,9 +74,9 @@ dependencies = [
[[package]]
name = "clap_derive"
version = "4.4.2"
version = "4.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873"
checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442"
dependencies = [
"heck",
"proc-macro2",
@ -86,9 +86,9 @@ dependencies = [
[[package]]
name = "clap_lex"
version = "0.5.1"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961"
checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1"
[[package]]
name = "colorchoice"
@ -125,9 +125,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]]
name = "hashbrown"
version = "0.14.1"
version = "0.14.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7dfda62a12f55daeae5015f81b0baea145391cb4520f86c248fc615d72640d12"
checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156"
[[package]]
name = "heck"

View File

@ -8,7 +8,7 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
clap = { version = "4.4.6", features = ["derive"] }
clap = { version = "4.4.7", features = ["derive"] }
csv = "1.3.0"
serde = { version = "1.0.189", features = ["std", "derive"] }
serde_json = "1.0.107"

View File

@ -1,23 +1,28 @@
use crate::types::fact::{FactData, Fact};
use crate::types::fact::Fact;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::env;
pub struct EnvironmentData {}
impl EnvironmentData {}
impl EnvironmentData {
#[derive(Serialize, Deserialize)]
pub struct EnvironmentValue {
key: String,
value: String,
time_set: u128,
}
impl Fact for EnvironmentData {
fn gather(&self) -> Vec<FactData>{
let mut vfd: Vec<FactData> = vec![];
let time_set = self.get_epoch_ms();
fn gather(&self) -> String {
let mut outmap: Vec<Value> = vec![];
for (key, value) in env::vars() {
let fd = FactData{
name: String::from("env_") + &key,
value: value,
time_set: time_set
};
vfd.push(fd);
let entry = json!({
"key": &key,
"value": value,
});
outmap.append(&mut vec![entry]);
}
return vfd;
serde_json::to_string(&outmap).unwrap()
}
}

View File

@ -1,107 +1,29 @@
use crate::{types::fact::{Fact, FactData}, util::command::get_result_as_string};
use crate::{types::fact::Fact, util::command::get_result_as_string};
use serde::{Deserialize, Serialize};
use serde_json::Value;
#[derive(Serialize, Deserialize)]
pub struct IPData {}
impl IPData {}
#[derive(Serialize, Deserialize)]
struct IpAddrInfo {
family: String,
local: String,
prefixlen: i32,
broadcast: Option<String>,
scope: String,
dynamic: Option<bool>,
noprefixroute: Option<bool>,
label: Option<String>,
valid_life_time: i64,
preferred_life_time: i64,
}
#[derive(Serialize, Deserialize)]
struct IpAddr {
ifindex: i32,
ifname: String,
flags: Vec<String>,
mtu: i32,
qdisc: String,
operstate: String,
group: String,
txqlen: i32,
link_type: String,
address: Option<String>,
broadcast: Option<String>,
addr_info: Vec<IpAddrInfo>,
}
impl Fact for IPData {
fn gather(&self) -> Vec<FactData> {
let mut vfd: Vec<FactData> = vec![];
let time_set = self.get_epoch_ms();
let ips: Vec<IpAddr> = serde_json::from_str(get_result_as_string("ip", vec!["-j", "addr"]).as_str()).unwrap();
for ip in ips {
if ip.ifname != "lo" {
for addr_info in ip.addr_info {
let fd = FactData {
name: format!("ip_addr_{}_{}_addr", ip.ifname, addr_info.family),
value: addr_info.local,
time_set: time_set,
};
vfd.push(fd);
vfd.push(FactData {
name: format!("ip_addr_{}_{}_prefixlen", ip.ifname, addr_info.family),
value: addr_info.prefixlen.to_string(),
time_set: time_set,
});
if addr_info.label.is_some() {
vfd.push(FactData {
name: format!("ip_addr_{}_{}_label", ip.ifname, addr_info.family),
value: addr_info.label.unwrap(),
time_set: time_set,
});
}
if addr_info.broadcast.is_some() {
vfd.push(FactData {
name: format!("ip_addr_{}_{}_broadcast", ip.ifname, addr_info.family),
value: addr_info.broadcast.unwrap(),
time_set: time_set,
});
}
if ip.address.is_some() {
vfd.push(FactData {
name: format!("ip_addr_{}_macaddr", ip.ifname),
value: ip.address.clone().unwrap(),
time_set: time_set,
})
}
}
}
}
return vfd;
fn gather(&self) -> String {
let res = get_result_as_string("ip", vec!["-j", "addr"]);
let jsonres: Value = serde_json::from_str(res.as_str()).unwrap();
let out = json!({ "ip_addr": jsonres });
out.to_string()
}
}
pub struct IPRouteData {}
impl IPRouteData {}
#[derive(Serialize, Deserialize)]
struct IpRoute {
dst: String,
gateway: Option<String>,
dev: String,
protocol: Option<String>,
metric: Option<i32>,
flags: Vec<String>,
scope: String,
prefsrc: String,
}
impl Fact for IpRoute {
fn gather(&self) -> Vec<FactData> {
let mut vfd: Vec<FactData> = vec![];
let time_set = self.get_epoch_ms();
let routes: Vec<IpRoute> = serde_json::from_str(get_result_as_string("ip", vec!["-j", "route"]).as_str()).unwrap();
return vfd;
impl Fact for IPRouteData {
fn gather(&self) -> String {
let res = get_result_as_string("ip", vec!["-j", "route"]);
let jsonres: Value = serde_json::from_str(res.as_str()).unwrap();
let out = json!({
"ip_route": jsonres
});
out.to_string()
}
}

View File

@ -1,14 +1,16 @@
mod types;
mod gatherers;
mod types;
mod util;
use std::collections::HashSet;
use crate::types::fact::{Fact, FactData};
use crate::gatherers::environment::EnvironmentData;
use crate::gatherers::ip::IPData;
use clap::Parser;
use csv::Writer;
#[macro_use]
extern crate serde_json;
use crate::gatherers::environment::EnvironmentData;
use crate::gatherers::ip::{IPData, IPRouteData};
use crate::types::fact::Fact;
use clap::Parser;
use serde_json::Value;
use std::collections::{HashMap, HashSet};
#[derive(Parser)]
#[clap(author, version, about, long_about = None)]
@ -17,69 +19,61 @@ struct Args {
#[arg(short, long)]
gatherer: Option<Vec<String>>,
/// Output format, yaml, json are supported
#[arg(short, long, default_value="yaml")]
#[arg(short, long, default_value = "yaml")]
output: String,
}
fn gather_all() -> Vec<FactData>{
let mut data: Vec<FactData> = vec![];
data.append(&mut gather(&EnvironmentData{}));
data.append(&mut gather(&IPData{}));
return data;
}
fn gather_list(gatherers: HashSet<String>) -> Vec<FactData> {
let mut data: Vec<FactData> = vec![];
fn gather_list(gatherers: HashSet<String>, output: &str) -> String {
let mut outmap: HashMap<String, Value> = HashMap::new();
for g in gatherers {
match g.as_str() {
"all" => for d in gather_all(){
data.push(d);
},
"env" => for d in gather(&EnvironmentData{}) {
data.push(d);
},
"ip" => for d in gather(&IPData{}) {
data.push(d);
"env" => {
outmap.insert(
"environment".to_string(),
serde_json::from_str(&EnvironmentData {}.gather()).unwrap(),
);
}
_ => for d in gather_all() {
data.push(d);
"ipaddr" => {
outmap.insert(
"ipaddr".to_string(),
serde_json::from_str(&IPData {}.gather()).unwrap(),
);
}
"iproute" => {
outmap.insert(
"iproute".to_string(),
serde_json::from_str(&IPRouteData {}.gather()).unwrap(),
);
}
x => {
println!("unknown gatherer: {x}");
}
};
}
return data;
}
fn gather (t: &dyn Fact) -> Vec<FactData> {
return t.gather();
match output {
"json" => serde_json::to_string(&outmap).unwrap(),
"yaml" => serde_yaml::to_string(&outmap).unwrap(),
x => format!("Unknown output format {x}"),
}
}
fn main() {
let args = Args::parse();
let mut data:Vec<FactData> = vec![];
if args.gatherer.is_none() {
data.append(&mut gather_all());
} else {
// sanitize the gatherer list
let ugatherers: HashSet<String> = match &args.gatherer {
Some(x) => x.into_iter().map(|name| name).cloned().collect::<HashSet<String>>(),
None => HashSet::<String>::new(),
let output_format = match args.output.as_str() {
"json" => "json",
"yaml" => "yaml",
_ => "yaml",
};
data.append(&mut gather_list(ugatherers));
let all: HashSet<String> = HashSet::from([
"env".to_string(),
"ipaddr".to_string(),
"iproute".to_string(),
]);
let data_output: String = match args.gatherer {
None => gather_list(all, output_format),
Some(x) => {
let gatherers: HashSet<String> = x.into_iter().collect::<HashSet<String>>();
gather_list(gatherers, output_format)
}
match args.output.as_str() {
"json" => {
let serialized_json = serde_json::to_string(&data).unwrap();
println!("{}", serialized_json);
},
"csv" => {
let mut writer = Writer::from_writer(vec![]);
for fd in data {
writer.serialize(fd).unwrap();
}
println!("{}", String::from_utf8(writer.into_inner().unwrap()).unwrap());
}
&_ => {
let serialized_yaml = serde_yaml::to_string(&data).unwrap();
println!("{}", serialized_yaml);
},
};
println!("{}", data_output);
}

View File

@ -1,15 +1,7 @@
use std::time::{UNIX_EPOCH, SystemTime};
use serde::{Serialize, Deserialize};
use std::time::{SystemTime, UNIX_EPOCH};
#[derive(Serialize, Deserialize)]
pub struct FactData {
pub name: String,
pub value: String,
pub time_set: u128,
}
pub trait Fact : Send + Sync {
fn gather(&self) -> Vec<FactData>;
pub trait Fact: Send + Sync {
fn gather(&self) -> String;
fn get_epoch_ms(&self) -> u128 {
SystemTime::now()

View File

@ -10,33 +10,35 @@ fn get_output_from_command(cmd: &str, args: Vec<&str>) -> Output {
fn get_stdout_as_string(output: Output) -> String {
return match String::from_utf8(output.stdout) {
Ok(x) => x.strip_suffix("\n").unwrap().to_string(),
Err(e) => e.to_string()
}
Err(e) => e.to_string(),
};
}
fn get_stderr_as_string(output: Output) -> String {
return match String::from_utf8(output.stderr) {
Ok(x) => x.strip_suffix("\n").unwrap().to_string(),
Err(e) => e.to_string()
}
Err(e) => e.to_string(),
};
}
pub fn get_result_as_string(cmd: &str, args:Vec<&str>) -> String {
pub fn get_result_as_string(cmd: &str, args: Vec<&str>) -> String {
let output = get_output_from_command(cmd, args);
match output.status.code() {
Some(0) => get_stdout_as_string(output),
_ => get_stderr_as_string(output)
_ => get_stderr_as_string(output),
}
}
#[cfg(test)]
mod tests {
use crate::util::command::{get_result_as_string};
use crate::util::command::get_result_as_string;
#[test]
fn test_get_output_from_command() {
assert_eq!("Linux", get_result_as_string("uname", vec![]));
assert_eq!("ls: cannot access '/dev/mouse': No such file or directory",
get_result_as_string("ls", vec!["/dev/mouse",]))
assert_eq!(
"ls: cannot access '/dev/mouse': No such file or directory",
get_result_as_string("ls", vec!["/dev/mouse",])
)
}
}