Disconnect all containers before removing network
The list of attached containers is determined, all of them are disconnected from the network, then the network is deleted. * set net mask in unbound conf template * expose container id
This commit is contained in:
parent
820f1c3447
commit
2289567998
@ -54,6 +54,7 @@ impl Container {
|
|||||||
command
|
command
|
||||||
.args(["run", "--rm", "--detach", "--name", &name])
|
.args(["run", "--rm", "--detach", "--name", &name])
|
||||||
.arg("-it")
|
.arg("-it")
|
||||||
|
.args(["--network", network.name()])
|
||||||
.arg(image_tag)
|
.arg(image_tag)
|
||||||
.args(["sleep", "infinity"]);
|
.args(["sleep", "infinity"]);
|
||||||
|
|
||||||
@ -154,6 +155,10 @@ impl Container {
|
|||||||
pub fn ipv4_addr(&self) -> Ipv4Addr {
|
pub fn ipv4_addr(&self) -> Ipv4Addr {
|
||||||
self.inner.ipv4_addr
|
self.inner.ipv4_addr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn id(&self) -> &str {
|
||||||
|
&self.inner.id
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn container_count() -> usize {
|
fn container_count() -> usize {
|
||||||
|
@ -24,7 +24,7 @@ impl Network {
|
|||||||
let mut command = Command::new("docker");
|
let mut command = Command::new("docker");
|
||||||
command
|
command
|
||||||
.args(["network", "create"])
|
.args(["network", "create"])
|
||||||
.args(["--internal"])
|
.args(["--internal", "--attachable"])
|
||||||
.arg(&network_name);
|
.arg(&network_name);
|
||||||
|
|
||||||
// create network
|
// create network
|
||||||
@ -49,6 +49,11 @@ impl Network {
|
|||||||
pub fn name(&self) -> &str {
|
pub fn name(&self) -> &str {
|
||||||
self.name.as_str()
|
self.name.as_str()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the subnet mask
|
||||||
|
pub fn netmask(&self) -> &str {
|
||||||
|
&self.config.subnet
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Collects all important configs.
|
/// Collects all important configs.
|
||||||
@ -85,7 +90,20 @@ impl Drop for Network {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Removes the given network.
|
||||||
fn remove_network(network_name: &str) -> Result<ExitStatus> {
|
fn remove_network(network_name: &str) -> Result<ExitStatus> {
|
||||||
|
// Disconnects all attached containers
|
||||||
|
for container_id in get_attached_containers(network_name)? {
|
||||||
|
let mut command = Command::new("docker");
|
||||||
|
let _ = command
|
||||||
|
.args(["network", "disconnect", "--force"])
|
||||||
|
.args([network_name, container_id.as_str()])
|
||||||
|
.stdout(Stdio::null())
|
||||||
|
.stderr(Stdio::null())
|
||||||
|
.status()?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the network
|
||||||
let mut command = Command::new("docker");
|
let mut command = Command::new("docker");
|
||||||
command
|
command
|
||||||
.args(["network", "rm", "--force", network_name])
|
.args(["network", "rm", "--force", network_name])
|
||||||
@ -94,6 +112,35 @@ fn remove_network(network_name: &str) -> Result<ExitStatus> {
|
|||||||
Ok(command.status()?)
|
Ok(command.status()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Finds the list of connected containers
|
||||||
|
fn get_attached_containers(network_name: &str) -> Result<Vec<String>> {
|
||||||
|
let mut command = Command::new("docker");
|
||||||
|
command.args([
|
||||||
|
"network",
|
||||||
|
"inspect",
|
||||||
|
network_name,
|
||||||
|
"-f",
|
||||||
|
r#"{{ range $k, $v := .Containers }}{{ printf "%s\n" $k }}{{ end }}"#,
|
||||||
|
]);
|
||||||
|
|
||||||
|
let output = command.output()?;
|
||||||
|
let container_ids = match output.status.success() {
|
||||||
|
true => {
|
||||||
|
let container_ids = std::str::from_utf8(&output.stdout)?
|
||||||
|
.trim()
|
||||||
|
.to_string()
|
||||||
|
.lines()
|
||||||
|
.filter(|line| !line.trim().is_empty())
|
||||||
|
.map(|line| line.to_string())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
container_ids
|
||||||
|
}
|
||||||
|
false => vec![],
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(container_ids)
|
||||||
|
}
|
||||||
|
|
||||||
fn network_count() -> usize {
|
fn network_count() -> usize {
|
||||||
static COUNT: AtomicUsize = AtomicUsize::new(1);
|
static COUNT: AtomicUsize = AtomicUsize::new(1);
|
||||||
|
|
||||||
@ -102,6 +149,8 @@ fn network_count() -> usize {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use crate::{name_server::NameServer, FQDN};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -117,4 +166,22 @@ mod tests {
|
|||||||
assert!(config.is_ok());
|
assert!(config.is_ok());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn remove_network_works() -> Result<()> {
|
||||||
|
let network = Network::new().expect("Failed to create network");
|
||||||
|
let network_name = network.name().to_string();
|
||||||
|
let nameserver = NameServer::new(FQDN::ROOT, &network)?;
|
||||||
|
|
||||||
|
let container_ids = get_attached_containers(network.name())?;
|
||||||
|
assert_eq!(1, container_ids.len());
|
||||||
|
assert_eq!(&[nameserver.container_id().to_string()], &container_ids[..]);
|
||||||
|
|
||||||
|
drop(network);
|
||||||
|
|
||||||
|
let container_ids = get_attached_containers(&network_name)?;
|
||||||
|
assert!(container_ids.is_empty());
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -155,6 +155,10 @@ impl<'a> NameServer<'a, Stopped> {
|
|||||||
state: Running { child },
|
state: Running { child },
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn container_id(&self) -> &str {
|
||||||
|
self.container.id()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ZONES_DIR: &str = "/etc/nsd/zones";
|
const ZONES_DIR: &str = "/etc/nsd/zones";
|
||||||
|
@ -44,7 +44,10 @@ impl Resolver {
|
|||||||
Implementation::Unbound => {
|
Implementation::Unbound => {
|
||||||
container.cp("/etc/unbound/root.hints", &hints)?;
|
container.cp("/etc/unbound/root.hints", &hints)?;
|
||||||
|
|
||||||
container.cp("/etc/unbound/unbound.conf", &unbound_conf(use_dnssec))?;
|
container.cp(
|
||||||
|
"/etc/unbound/unbound.conf",
|
||||||
|
&unbound_conf(use_dnssec, network.netmask()),
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Implementation::Hickory => {
|
Implementation::Hickory => {
|
||||||
@ -95,8 +98,8 @@ kill -TERM $(cat {pidfile})"
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unbound_conf(use_dnssec: bool) -> String {
|
fn unbound_conf(use_dnssec: bool, netmask: &str) -> String {
|
||||||
minijinja::render!(include_str!("templates/unbound.conf.jinja"), use_dnssec => use_dnssec)
|
minijinja::render!(include_str!("templates/unbound.conf.jinja"), use_dnssec => use_dnssec, netmask => netmask)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hickory_conf(use_dnssec: bool) -> String {
|
fn hickory_conf(use_dnssec: bool) -> String {
|
||||||
|
@ -2,7 +2,7 @@ server:
|
|||||||
verbosity: 4
|
verbosity: 4
|
||||||
use-syslog: no
|
use-syslog: no
|
||||||
interface: 0.0.0.0
|
interface: 0.0.0.0
|
||||||
access-control: 172.17.0.0/16 allow
|
access-control: {{ netmask }} allow
|
||||||
root-hints: /etc/unbound/root.hints
|
root-hints: /etc/unbound/root.hints
|
||||||
{% if use_dnssec %}
|
{% if use_dnssec %}
|
||||||
trust-anchor-file: /etc/trusted-key.key
|
trust-anchor-file: /etc/trusted-key.key
|
||||||
|
Loading…
Reference in New Issue
Block a user