diff --git a/Cargo.toml b/Cargo.toml index f693817..8865c15 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,4 +8,4 @@ chrono = { version = "0.4.40", features = ["serde"] } reqwest = { version = "0.12.15", features = ["json"] } serde = { version = "1.0.219", features = ["derive"] } serde_json = "1.0.140" -tokio = { version = "1.44.2", features = ["macros", "time"] } +tokio = { version = "1.44.2", features = ["macros"] } diff --git a/flake.nix b/flake.nix index 5bf100c..c991a30 100644 --- a/flake.nix +++ b/flake.nix @@ -10,6 +10,7 @@ let pkgs = import nixpkgs { inherit system; }; naersk-lib = pkgs.callPackage naersk { }; + package_name = "hetzner_dns"; in { defaultPackage = naersk-lib.buildPackage ./.; diff --git a/src/client.rs b/src/client.rs index 2b2fc20..7c52deb 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1,11 +1,9 @@ use crate::*; use reqwest::{ Client, Method, Request, Url, - header::{HeaderMap, HeaderValue}, + header::HeaderValue, }; -use serde::{Serializer, de::Visitor}; -use serde_json::Value; -use std::{borrow::Borrow, collections::HashMap}; +use std::borrow::Borrow; #[derive(Debug, Clone, Serialize, Deserialize)] pub enum RecordType { @@ -108,7 +106,6 @@ impl HetznerDNSAPIClient { method, self.host.join(url).map_err(|e| { println!("url formatting error: {}", e); - () })?, ); req.headers_mut().append( @@ -120,11 +117,9 @@ impl HetznerDNSAPIClient { serde_json::to_string(&payload) .map_err(|e| { println!("body encoding error: {}", e); - () })? .into(), ); - println!("{:#?}", serde_json::to_string(&payload)); } let t = self .client @@ -132,23 +127,19 @@ impl HetznerDNSAPIClient { .await .map_err(|e| { println!("request execution error: {}", e); - () })? .error_for_status() .map_err(|e| { println!("request error: {}", e); - () })? .text() .await .map_err(|e| { println!("request decoding error: {}", e); - () })?; - Ok(serde_json::from_str::(&t).map_err(|e| { + serde_json::from_str::(&t).map_err(|e| { println!("json response parsing error: {}", e); - () - })?) + }) } pub async fn get_zones<'a>( diff --git a/src/main.rs b/src/main.rs index 96427f6..ffb5876 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,7 @@ -#![allow(dead_code, unused)] use crate::client::*; use crate::models::*; use core::panic; use serde::{Deserialize, Serialize}; -use std::ops::Sub; mod client; mod models; @@ -268,7 +266,7 @@ async fn main() { .into_iter() .next() .unwrap(); - let mut records = + let records = client.get_records(None, None, Some(zone.id)).await.unwrap(); println!("{:#?}", records); } @@ -287,9 +285,26 @@ async fn main() { .unwrap()[0] .id; ctx.record_context.records[0].zone_id = zone.to_string(); - println!("{:#?}", ctx.record_context.records); - if let Ok(record) = - client.create_records(ctx.record_context.records).await + if let Ok(record) = client + .create_records( + ctx.record_context + .records + .into_iter() + .flat_map(|r| { + r.name + .split(",") + .map(|s| RecordPayload { + zone_id: r.zone_id.clone(), + r#type: r.r#type.clone(), + name: String::from(s), + value: r.value.clone(), + ttl: r.ttl, + }) + .collect::>() + }) + .collect::>(), + ) + .await { println!("{:#?}", record); } @@ -317,10 +332,13 @@ async fn main() { ); } for old_record in records { - if let Some(mut new_record) = - records_iter.find(|r| r.name == old_record.name) - { - let mut old_record = old_record; + if let Some(new_record) = records_iter.find(|r| { + r.name == old_record.name + || r.name + .split(",") + .find(|s| *s == old_record.name) + .is_some() + }) { updated_records.push(( old_record.id, RecordPayload { @@ -333,7 +351,7 @@ async fn main() { )); } } - if updated_records.len() > 0 { + if !updated_records.is_empty() { let records = client.update_records(updated_records).await.unwrap(); eprintln!("Updated {} records", records.len()); } else { @@ -354,14 +372,80 @@ async fn main() { _ => panic!("how in the even"), } } else { - panic!("missing token!"); + panic!("missing token! set HETZNER_DNS_API_TOKEN or pass --token "); } } else { match ctx.mode { - Mode::Zone => println!("zone help"), - Mode::Record => println!("record help"), - Mode::PrimaryServer => println!("primary server help"), - _ => println!("full help"), + Mode::Zone => { + print_general_help(); + print_zone_help(); + } + Mode::Record => { + print_general_help(); + print_zone_help(); + } + Mode::PrimaryServer => { + print_general_help(); + print_primary_help(); + } + _ => { + print_general_help(); + print_zone_help(); + print_record_help(); + print_primary_help(); + } } } } + +fn print_general_help() { + println!( + " +Usage: hetzner_dns + +Not passing an option will yield this help page. + +Subjects: +- z|zones: manage zones/domains +- r|records: manage records for a zone +- p|primary: manage primary servers for a zone + +Actions (valid for all subjects): +- g|get +- c|create +- u|update +- d|delete" + ); +} + +fn print_zone_help() { + println!( + " +Zone options per action: +- g|get [--all] [--zone ] +- c|create [--name ] [--ttl ] +- u|update [--zone ] [--name ] [--ttl ] +- d|delete [--zone ]" + ); +} +fn print_record_help() { + println!( + " +Record options per action: +- g|get [--all] [--zone ] +- c|create [--zone ] [--name ] [--value ] [--ttl ] +- u|update [--zone ] [--name ] [--value ] [--ttl ] +- d|delete [--zone ] [--name ] +Create will update existing records and update will create them if nescessary. +--name supports comma separated values to create/update multiple records with same values. (wip) +--ttl is always otpional and defaults to 86400." + ); +} +fn print_primary_help() { + println!( + " +Missing implemention for primary servers - consider opening an issue at +https://git.thebread.dev/thebreadcompany/hetzner_dns/issues +if this feature is relevant for you!" + ); +}