init
This commit is contained in:
commit
4d683e9201
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
Cargo.lock
|
||||
target/
|
15
Cargo.toml
Normal file
15
Cargo.toml
Normal file
|
@ -0,0 +1,15 @@
|
|||
[package]
|
||||
name = "ykre"
|
||||
version = "0.1.0"
|
||||
authors = ["a-Sansara <dev]at[pluie]dot[org>"]
|
||||
edition = "2018"
|
||||
description = "Ykre is Yaml Kubernetes Resource Extractor"
|
||||
license = "MIT"
|
||||
readme = "README.md"
|
||||
keywords = ["cli", "yaml", "kubernetes", "kustomize"]
|
||||
categories = ["command-line-utilities"]
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
yaml-rust = "0.4"
|
31
README.md
Normal file
31
README.md
Normal file
|
@ -0,0 +1,31 @@
|
|||
# Ykre
|
||||
|
||||
**Ykre** is a small cli program written in rust wich purpose is to extract from a list
|
||||
of yaml documents, documents matching a specified condition. **Ykre** goal is to find
|
||||
specific Kubernetes Resource from the kustomize output.
|
||||
**Ykre** stands for **Y**aml **K**ubernetes **R**esources **E**ctractor.
|
||||
|
||||
## usage
|
||||
```
|
||||
ykre SEARCH [DEF]
|
||||
```
|
||||
|
||||
## examples
|
||||
|
||||
display content of the kubernetes resource 'myResourceName'
|
||||
```
|
||||
cat kubresources.yaml | ykre 'myResourceName'
|
||||
```
|
||||
write content of the kubernetes resource 'pv-dump' into a file
|
||||
```
|
||||
kustomize build ./config/volumes/local | ykre 'pv-dump' > ./tmp.yaml
|
||||
```
|
||||
retriew kubernetes pv resources matching 2Gi disk capacity
|
||||
```
|
||||
kustomize build ./config/volumes/dev | ykre 2Gi spec.capacity.storage
|
||||
```
|
||||
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
BIN
dist/ykre_0.1.0_amd64.deb
vendored
Normal file
BIN
dist/ykre_0.1.0_amd64.deb
vendored
Normal file
Binary file not shown.
29
src/main.rs
Normal file
29
src/main.rs
Normal file
|
@ -0,0 +1,29 @@
|
|||
extern crate yaml_rust;
|
||||
pub mod ykre;
|
||||
|
||||
use std::io;
|
||||
use std::panic;
|
||||
|
||||
const PANIC_BYPASS_FILE : &str = "src/ykre/pipin.rs";
|
||||
const PANIC_BYPASS_LINE : u32 = 9;
|
||||
|
||||
fn main() -> io::Result<()> {
|
||||
|
||||
panic::set_hook(Box::new(|_info| {
|
||||
let mut bypass :bool = false;
|
||||
if let Some(location) = &_info.location() {
|
||||
bypass = location.file() == PANIC_BYPASS_FILE && location.line() == PANIC_BYPASS_LINE;
|
||||
}
|
||||
if !bypass {
|
||||
//~ println!("{:?}", &_info);
|
||||
if let Some(s) = &_info.payload().downcast_ref::<&str>() {
|
||||
if s.len() > 1 {
|
||||
println!("{}", s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
ykre::run();
|
||||
Ok(())
|
||||
}
|
56
src/ykre.rs
Normal file
56
src/ykre.rs
Normal file
|
@ -0,0 +1,56 @@
|
|||
mod yaml;
|
||||
mod pipin;
|
||||
mod app;
|
||||
|
||||
pub use self::yaml::YamlDocument;
|
||||
pub use self::pipin::{spawn_stdin, sleep};
|
||||
pub use self::app::{run};
|
||||
|
||||
const YKRE_LIMIT_ATTEMPT : u64 = 900;
|
||||
const YKRE_SLEEP_START : u64 = 50;
|
||||
const YKRE_SLEEP_DATA : u64 = 1;
|
||||
const YKRE_SLEEP_NODATA : u64 = 1;
|
||||
const YKRE_DEFAULT_DEF : &str = "metadata.name";
|
||||
const YKRE_ERROR_NOTFOUND : &str = r"
|
||||
:: Ykre ::
|
||||
|
||||
error : no match found for specified pattern
|
||||
";
|
||||
const YKRE_ERROR_INVALID : &str = r"
|
||||
:: Ykre ::
|
||||
|
||||
error : invalid parameter. type ykre for usage
|
||||
";
|
||||
const YKRE_ERROR_NOPIPE : &str = r"
|
||||
:: Ykre ::
|
||||
|
||||
error : you must send data using pipe
|
||||
";
|
||||
const YKRE_HELP : &str = r"
|
||||
-----------------------------------------------------------------------------------
|
||||
:: Ykre :: v0.1 license : MIT - author : a-Sansara
|
||||
-----------------------------------------------------------------------------------
|
||||
|
||||
Ykre is a small program written in `rust` wich purpose is to extract from a list
|
||||
of yaml documents, documents matching a specified condition. Ykre goal is to find
|
||||
specific Kubernetes Resource from the kustomize output.
|
||||
Ykre stands for Yaml Kubernetes Resources Ectractor.
|
||||
|
||||
Usage :
|
||||
|
||||
ykre SEARCH [DEF]
|
||||
|
||||
you MUST use pipe with ykre command
|
||||
|
||||
SEARCH - value of kubernetes resource name
|
||||
DEF - the yaml node to look for
|
||||
(default : 'metadata.name', dot is the separator for embed nodes)
|
||||
|
||||
ex :
|
||||
# display content of the kubernetes resource 'myResourceName'
|
||||
cat kubresources.yaml | ykre 'myResourceName'
|
||||
# write content of the kubernetes resource 'pv-dump' into a file
|
||||
kustomize build ./config/volumes/local | ykre 'pv-dump' > ./tmp.yaml
|
||||
# retriew kubernetes pv resources matching 2Gi disk capacity
|
||||
kustomize build ./config/volumes/dev | ykre 2Gi spec.capacity.storage
|
||||
";
|
67
src/ykre/app.rs
Normal file
67
src/ykre/app.rs
Normal file
|
@ -0,0 +1,67 @@
|
|||
use std::panic;
|
||||
use std::env;
|
||||
use std::sync::mpsc::TryRecvError;
|
||||
|
||||
use crate::ykre::*;
|
||||
|
||||
pub fn find(search: &str, def: &str, data:String) {
|
||||
let doc = YamlDocument::load_str(data);
|
||||
let rs = doc.match_docs(&def, &search);
|
||||
if !rs.is_empty() {
|
||||
for i in rs.iter() {
|
||||
println!("{}", doc.dump(*i));
|
||||
}
|
||||
return
|
||||
}
|
||||
panic!(YKRE_ERROR_NOTFOUND);
|
||||
}
|
||||
|
||||
pub fn get_data(buf :&mut String, limit :u32) -> bool {
|
||||
let stdin = spawn_stdin();
|
||||
let mut attempt = 0;
|
||||
let mut has_data :bool = false;
|
||||
sleep(YKRE_SLEEP_START);
|
||||
while attempt < limit {
|
||||
let rs = match stdin.try_recv() {
|
||||
Ok(s) => s,
|
||||
Err(TryRecvError::Empty) => String::from(""),
|
||||
Err(TryRecvError::Disconnected) => String::from(""),
|
||||
};
|
||||
if !rs.is_empty() {
|
||||
*buf += &rs;
|
||||
has_data = true;
|
||||
}
|
||||
else if has_data {
|
||||
break;
|
||||
}
|
||||
attempt += 1;
|
||||
sleep(match has_data {
|
||||
true => YKRE_SLEEP_DATA,
|
||||
_ => YKRE_SLEEP_NODATA,
|
||||
});
|
||||
}
|
||||
return has_data
|
||||
}
|
||||
|
||||
pub fn run() {
|
||||
let args: Vec<String> = env::args().collect();
|
||||
if args.len() == 1 {
|
||||
println!("{}", YKRE_HELP);
|
||||
return
|
||||
}
|
||||
else if args.len() > 1 && args.len() <= 3 {
|
||||
|
||||
let mut buf :String = String::from("");
|
||||
let search :&str = &args[1];
|
||||
let def :&str = match args.len() {
|
||||
3 => &args[2],
|
||||
_ => YKRE_DEFAULT_DEF,
|
||||
};
|
||||
let limit : u32 = env::var("YKRE_LIMIT_ATTEMPT").unwrap_or(format!("{}", YKRE_LIMIT_ATTEMPT).to_owned()).parse::<u32>().unwrap();
|
||||
if get_data(&mut buf, limit) {
|
||||
return find(search, def, buf);
|
||||
}
|
||||
panic!(YKRE_ERROR_NOPIPE)
|
||||
}
|
||||
panic!(YKRE_ERROR_INVALID)
|
||||
}
|
17
src/ykre/pipin.rs
Normal file
17
src/ykre/pipin.rs
Normal file
|
@ -0,0 +1,17 @@
|
|||
use std::{io, thread, time, sync::mpsc};
|
||||
use std::sync::mpsc::Receiver;
|
||||
|
||||
pub fn spawn_stdin() -> Receiver<String> {
|
||||
let (tx, rx) = mpsc::channel::<String>();
|
||||
let _child = thread::spawn(move || loop {
|
||||
let mut buffer = String::new();
|
||||
io::stdin().read_line(&mut buffer).unwrap();
|
||||
tx.send(buffer).unwrap()
|
||||
});
|
||||
rx
|
||||
}
|
||||
|
||||
pub fn sleep(millis: u64) {
|
||||
let duration = time::Duration::from_millis(millis);
|
||||
thread::sleep(duration);
|
||||
}
|
68
src/ykre/yaml.rs
Normal file
68
src/ykre/yaml.rs
Normal file
|
@ -0,0 +1,68 @@
|
|||
use yaml_rust::{YamlLoader, Yaml, YamlEmitter};
|
||||
use std::vec::Vec;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct YamlDocument {
|
||||
path: String,
|
||||
content: String,
|
||||
docs: Vec<yaml_rust::Yaml>
|
||||
}
|
||||
|
||||
impl YamlDocument {
|
||||
|
||||
fn loaded_from(content: String, source: Option<String>) -> YamlDocument {
|
||||
let docs = YamlLoader::load_from_str(&content).unwrap();
|
||||
let path = source.unwrap_or("".to_owned());
|
||||
YamlDocument { path, content, docs }
|
||||
}
|
||||
|
||||
pub fn load_str(content: String) -> YamlDocument {
|
||||
Self::loaded_from(content, None)
|
||||
}
|
||||
|
||||
pub fn find_str(&self, path: &str, index: usize) -> Option<&str> {
|
||||
let search = path.to_string();
|
||||
let v: Vec<&str> = search.split(".").collect();
|
||||
let mut node: &Yaml = &self.docs[index];
|
||||
for key in &v {
|
||||
node = &node[*key];
|
||||
}
|
||||
node.as_str().clone()
|
||||
}
|
||||
|
||||
pub fn dump(&self, index: usize) -> String {
|
||||
let doc = &self.docs[index];
|
||||
let mut out_str = String::new();
|
||||
{
|
||||
let mut emitter = YamlEmitter::new(&mut out_str);
|
||||
emitter.dump(doc).unwrap();
|
||||
}
|
||||
out_str
|
||||
}
|
||||
|
||||
pub fn match_doc(&self, search: &str, matched: &str) -> Option<usize> {
|
||||
let mut index = 0;
|
||||
let mut rs: Option<usize> = None;
|
||||
while index < self.docs.len() {
|
||||
match &self.find_str(search, index) {
|
||||
Some(ref s) if s == &matched => rs = Some(index),
|
||||
_ => (),
|
||||
}
|
||||
index += 1;
|
||||
}
|
||||
rs
|
||||
}
|
||||
|
||||
pub fn match_docs(&self, search: &str, matched: &str) -> Vec<usize> {
|
||||
let mut v: Vec<usize> = Vec::new();
|
||||
let mut index = 0;
|
||||
while index < self.docs.len() {
|
||||
match &self.find_str(search, index) {
|
||||
Some(ref s) if s == &matched => v.push(index),
|
||||
_ => (),
|
||||
}
|
||||
index += 1;
|
||||
}
|
||||
v
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user