From 42de7c3a92bdedbd02e1fd5c77a3089c4b5ccf32 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 2 Feb 2024 15:19:29 +0100 Subject: [PATCH] move NsdContainer into its own module --- src/lib.rs | 117 ++--------------------------------------------------- src/nsd.rs | 115 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 118 insertions(+), 114 deletions(-) create mode 100644 src/nsd.rs diff --git a/src/lib.rs b/src/lib.rs index 40113604..a6eab726 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,45 +1,14 @@ use core::fmt; -use std::process::Child; -use container::Container; -use minijinja::{context, Environment}; +pub use crate::nsd::NsdContainer; pub type Error = Box; pub type Result = core::result::Result; const CHMOD_RW_EVERYONE: &str = "666"; -fn tld_zone(domain: &str) -> String { - assert!(domain.ends_with(".")); - assert!(!domain.starts_with(".")); - - let mut env = Environment::new(); - let name = "main.zone"; - env.add_template(name, include_str!("templates/tld.zone.jinja")) - .unwrap(); - let template = env.get_template(name).unwrap(); - template.render(context! { tld => domain }).unwrap() -} - -fn root_zone() -> String { - let mut env = Environment::new(); - let name = "main.zone"; - env.add_template(name, include_str!("templates/root.zone.jinja")) - .unwrap(); - let template = env.get_template(name).unwrap(); - template.render(context! {}).unwrap() -} - -fn nsd_conf(domain: &str) -> String { - assert!(domain.ends_with(".")); - - let mut env = Environment::new(); - let name = "nsd.conf"; - env.add_template(name, include_str!("templates/nsd.conf.jinja")) - .unwrap(); - let template = env.get_template(name).unwrap(); - template.render(context! { domain => domain }).unwrap() -} +mod container; +mod nsd; pub enum Domain<'a> { Root, @@ -55,49 +24,6 @@ impl Domain<'_> { } } -pub struct NsdContainer { - child: Child, - container: Container, -} - -impl NsdContainer { - pub fn start(domain: Domain) -> Result { - let container = Container::run(Image::Nsd)?; - - container.exec(&["mkdir", "-p", "/etc/nsd/zones"])?; - let zone_path = "/etc/nsd/zones/main.zone"; - - container.cp( - "/etc/nsd/nsd.conf", - &nsd_conf(domain.fqdn()), - CHMOD_RW_EVERYONE, - )?; - - let zone_file_contents = match domain { - Domain::Root => root_zone(), - Domain::Tld { domain } => tld_zone(domain), - }; - - container.cp(zone_path, &zone_file_contents, CHMOD_RW_EVERYONE)?; - - let child = container.spawn(&["nsd", "-d"])?; - - Ok(Self { child, container }) - } - - pub fn ip_addr(&self) -> Result { - self.container.ip_addr() - } -} - -impl Drop for NsdContainer { - fn drop(&mut self) { - let _ = self.child.kill(); - } -} - -mod container; - pub enum Image { Nsd, // for ROOT, TLD, DOMAIN Unbound, @@ -114,40 +40,3 @@ impl fmt::Display for Image { f.write_str(name) } } - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn tld_setup() -> Result<()> { - let tld_ns = NsdContainer::start(Domain::Tld { domain: "com." })?; - let ip_addr = tld_ns.ip_addr()?; - - let client = Container::run(Image::Client)?; - let output = client.exec(&["dig", &format!("@{ip_addr}"), "SOA", "com."])?; - - assert!(output.status.success()); - let stdout = core::str::from_utf8(&output.stdout)?; - println!("{stdout}"); - assert!(stdout.contains("status: NOERROR")); - - Ok(()) - } - - #[test] - fn root_setup() -> Result<()> { - let root_ns = NsdContainer::start(Domain::Root)?; - let ip_addr = root_ns.ip_addr()?; - - let client = Container::run(Image::Client)?; - let output = client.exec(&["dig", &format!("@{ip_addr}"), "SOA", "."])?; - - assert!(output.status.success()); - let stdout = core::str::from_utf8(&output.stdout)?; - println!("{stdout}"); - assert!(stdout.contains("status: NOERROR")); - - Ok(()) - } -} diff --git a/src/nsd.rs b/src/nsd.rs new file mode 100644 index 00000000..4d434214 --- /dev/null +++ b/src/nsd.rs @@ -0,0 +1,115 @@ +use std::process::Child; + +use minijinja::{context, Environment}; + +use crate::{container::Container, Domain, Image, Result, CHMOD_RW_EVERYONE}; + +pub struct NsdContainer { + child: Child, + container: Container, +} + +impl NsdContainer { + pub fn start(domain: Domain) -> Result { + let container = Container::run(Image::Nsd)?; + + container.exec(&["mkdir", "-p", "/etc/nsd/zones"])?; + let zone_path = "/etc/nsd/zones/main.zone"; + + container.cp( + "/etc/nsd/nsd.conf", + &nsd_conf(domain.fqdn()), + CHMOD_RW_EVERYONE, + )?; + + let zone_file_contents = match domain { + Domain::Root => root_zone(), + Domain::Tld { domain } => tld_zone(domain), + }; + + container.cp(zone_path, &zone_file_contents, CHMOD_RW_EVERYONE)?; + + let child = container.spawn(&["nsd", "-d"])?; + + Ok(Self { child, container }) + } + + pub fn ip_addr(&self) -> Result { + self.container.ip_addr() + } +} + +impl Drop for NsdContainer { + fn drop(&mut self) { + let _ = self.child.kill(); + } +} + +fn tld_zone(domain: &str) -> String { + assert!(domain.ends_with(".")); + assert!(!domain.starts_with(".")); + + let mut env = Environment::new(); + let name = "main.zone"; + env.add_template(name, include_str!("templates/tld.zone.jinja")) + .unwrap(); + let template = env.get_template(name).unwrap(); + template.render(context! { tld => domain }).unwrap() +} + +fn root_zone() -> String { + let mut env = Environment::new(); + let name = "main.zone"; + env.add_template(name, include_str!("templates/root.zone.jinja")) + .unwrap(); + let template = env.get_template(name).unwrap(); + template.render(context! {}).unwrap() +} + +fn nsd_conf(domain: &str) -> String { + assert!(domain.ends_with(".")); + + let mut env = Environment::new(); + let name = "nsd.conf"; + env.add_template(name, include_str!("templates/nsd.conf.jinja")) + .unwrap(); + let template = env.get_template(name).unwrap(); + template.render(context! { domain => domain }).unwrap() +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn tld_setup() -> Result<()> { + let tld_ns = NsdContainer::start(Domain::Tld { domain: "com." })?; + let ip_addr = tld_ns.ip_addr()?; + + let client = Container::run(Image::Client)?; + let output = client.exec(&["dig", &format!("@{ip_addr}"), "SOA", "com."])?; + + assert!(output.status.success()); + let stdout = core::str::from_utf8(&output.stdout)?; + println!("{stdout}"); + assert!(stdout.contains("status: NOERROR")); + + Ok(()) + } + + #[test] + fn root_setup() -> Result<()> { + let root_ns = NsdContainer::start(Domain::Root)?; + let ip_addr = root_ns.ip_addr()?; + + let client = Container::run(Image::Client)?; + let output = client.exec(&["dig", &format!("@{ip_addr}"), "SOA", "."])?; + + assert!(output.status.success()); + let stdout = core::str::from_utf8(&output.stdout)?; + println!("{stdout}"); + assert!(stdout.contains("status: NOERROR")); + + Ok(()) + } +}