mirror of
https://github.com/vbrandl/bind9-api.git
synced 2025-08-19 06:35:34 +02:00
Initial commit
This commit is contained in:
18
client/src/cli.rs
Normal file
18
client/src/cli.rs
Normal file
@@ -0,0 +1,18 @@
|
||||
pub fn parse_cli() -> ::clap::ArgMatches<'static> {
|
||||
clap_app!(bind9_api_client =>
|
||||
(version: crate_version!())
|
||||
(author: crate_authors!())
|
||||
(about: crate_description!())
|
||||
(@arg CONFIG: -c --config +takes_value "Path to config file (Defaults to /etc/bind9apiclient.toml)")
|
||||
(@arg DOMAIN: -d --domain +takes_value +required "Domain to create")
|
||||
(@arg RECORD: -r --record +takes_value "The record type (Defaults to TXT)")
|
||||
(@subcommand update =>
|
||||
(about: "Creates a new record")
|
||||
(@arg VALUE: -v --value +takes_value +required "Value to write in the record")
|
||||
(@arg TTL: -t --ttl + takes_value "TTL of the record (Defaults to 8640)")
|
||||
)
|
||||
(@subcommand delete =>
|
||||
(about: "Deletes a record")
|
||||
)
|
||||
).get_matches()
|
||||
}
|
114
client/src/main.rs
Normal file
114
client/src/main.rs
Normal file
@@ -0,0 +1,114 @@
|
||||
#[macro_use]
|
||||
extern crate clap;
|
||||
extern crate crypto;
|
||||
extern crate data;
|
||||
extern crate failure;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
extern crate openssl_probe;
|
||||
extern crate pretty_env_logger;
|
||||
extern crate reqwest;
|
||||
extern crate serde;
|
||||
extern crate toml;
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
extern crate serde_json;
|
||||
|
||||
mod cli;
|
||||
|
||||
use failure::Error;
|
||||
|
||||
use data::{ApiError, Delete, Record, Update};
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
#[derive(Eq, PartialEq, Clone, Copy)]
|
||||
enum Method {
|
||||
POST,
|
||||
DELETE,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct Config<'a> {
|
||||
#[serde(borrow)]
|
||||
host: Cow<'a, str>,
|
||||
#[serde(borrow)]
|
||||
secret: Cow<'a, str>,
|
||||
}
|
||||
|
||||
fn delete(config: &Config, record: Record, domain: &str) -> Result<()> {
|
||||
let delete = Delete::new(domain.to_owned(), record);
|
||||
let res = call_api(config, delete, Method::DELETE)?;
|
||||
if res.status().is_success() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(ApiError::RequestError.into())
|
||||
}
|
||||
}
|
||||
|
||||
fn update(config: &Config, record: Record, domain: &str, value: &str, ttl: u32) -> Result<()> {
|
||||
let update = Update::new(domain.to_owned(), value.to_owned(), record, ttl);
|
||||
let res = call_api(config, update, Method::POST)?;
|
||||
if res.status().is_success() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(ApiError::RequestError.into())
|
||||
}
|
||||
}
|
||||
|
||||
fn call_api<D: serde::Serialize>(
|
||||
config: &Config,
|
||||
data: D,
|
||||
method: Method,
|
||||
) -> Result<reqwest::Response> {
|
||||
let data_s = serde_json::to_string(&data)?;
|
||||
info!("body: {}", data_s);
|
||||
let signature = crypto::sign(config.secret.as_bytes(), data_s.as_bytes());
|
||||
let signature = crypto::bytes_to_hex_str(&signature)?;
|
||||
let client = reqwest::Client::new();
|
||||
let url = format!("{}/record", config.host);
|
||||
Ok(if method == Method::POST {
|
||||
client.post(&url)
|
||||
} else {
|
||||
client.delete(&url)
|
||||
}.header(data::XApiToken(signature))
|
||||
.json(&data)
|
||||
.send()?)
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
openssl_probe::init_ssl_cert_env_vars();
|
||||
std::env::set_var("RUST_LOG", "info");
|
||||
pretty_env_logger::init();
|
||||
let matches = cli::parse_cli();
|
||||
let record: Record = matches
|
||||
.value_of("RECORD")
|
||||
.unwrap_or("TXT")
|
||||
.parse()
|
||||
.expect("Invalid record type");
|
||||
let domain = matches.value_of("DOMAIN").unwrap();
|
||||
let config_path = matches
|
||||
.value_of("CONFIG")
|
||||
.unwrap_or("/etc/bind9apiclient.toml");
|
||||
let config = std::fs::read_to_string(config_path).expect("Cannot read config file");
|
||||
let config: Config = toml::from_str(&config).expect("Cannot parse config file");
|
||||
if let Some(matches) = matches.subcommand_matches("update") {
|
||||
let ttl = matches
|
||||
.value_of("TTL")
|
||||
.unwrap_or("8640")
|
||||
.parse()
|
||||
.expect("Cannot parse TTL");
|
||||
update(
|
||||
&config,
|
||||
record,
|
||||
domain,
|
||||
matches.value_of("VALUE").unwrap(),
|
||||
ttl,
|
||||
)?;
|
||||
} else if matches.subcommand_matches("delete").is_some() {
|
||||
delete(&config, record, domain)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
Reference in New Issue
Block a user