Skip to content

Commit

Permalink
Merge pull request #503 from flouthoc/netavark-network-update
Browse files Browse the repository at this point in the history
update: add support for `netavark update` command
  • Loading branch information
openshift-merge-robot authored Dec 5, 2022
2 parents 1669ecd + 0c61f05 commit f7186d3
Show file tree
Hide file tree
Showing 8 changed files with 177 additions and 28 deletions.
1 change: 1 addition & 0 deletions src/commands/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod setup;
pub mod teardown;
pub mod update;
pub mod version;
14 changes: 1 addition & 13 deletions src/commands/setup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ use crate::network::{core_utils, types};
use clap::Parser;
use log::{debug, error, info};
use std::collections::HashMap;
use std::env;
use std::fs::{self};
use std::path::Path;

Expand Down Expand Up @@ -51,18 +50,7 @@ impl Setup {

let mut response: HashMap<String, types::StatusBlock> = HashMap::new();

let dns_port = match env::var("NETAVARK_DNS_PORT") {
Ok(port_string) => match port_string.parse() {
Ok(port) => port,
Err(e) => {
return Err(NetavarkError::Message(format!(
"Invalid NETAVARK_DNS_PORT {}: {}",
port_string, e
)))
}
},
Err(_) => 53,
};
let dns_port = core_utils::get_netavark_dns_port()?;

let (mut hostns, mut netns) =
core_utils::open_netlink_sockets(&self.network_namespace_path)?;
Expand Down
16 changes: 1 addition & 15 deletions src/commands/teardown.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use crate::network::driver::{get_network_driver, DriverInfo};
use crate::{firewall, network};
use clap::Parser;
use log::debug;
use std::env;
use std::path::Path;

#[derive(Parser, Debug)]
Expand Down Expand Up @@ -36,20 +35,7 @@ impl Teardown {

let mut error_list = NetavarkErrorList::new();

let dns_port = match env::var("NETAVARK_DNS_PORT") {
Ok(port_string) => match port_string.parse() {
Ok(port) => port,
Err(e) => {
error_list.push(NetavarkError::Message(format!(
"Invalid NETAVARK_DNS_PORT {}: {}",
port_string, e
)));
// default to 53 if there is a error here, we should not prevent cleanup because of it
53
}
},
Err(_) => 53,
};
let dns_port = core_utils::get_netavark_dns_port()?;

if Path::new(&aardvark_bin).exists() {
// stop dns server first before netavark clears the interface
Expand Down
59 changes: 59 additions & 0 deletions src/commands/update.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
use crate::dns::aardvark::Aardvark;
use crate::error::{NetavarkError, NetavarkResult};
use crate::network::core_utils;

use clap::Parser;
use log::debug;
use std::path::Path;

#[derive(Parser, Debug)]
pub struct Update {
/// Network name to update
#[clap(forbid_empty_values = true, required = true)]
network_name: String,
/// DNS Servers to update for the network
#[clap(long, required = true, forbid_empty_values = true)]
network_dns_servers: Vec<String>,
}

impl Update {
/// Updates network dns servers for an already configured network
pub fn new(network_name: String, network_dns_servers: Vec<String>) -> Self {
Self {
network_name,
network_dns_servers,
}
}

pub fn exec(
&self,
config_dir: String,
aardvark_bin: String,
rootless: bool,
) -> NetavarkResult<()> {
let dns_port = core_utils::get_netavark_dns_port()?;

if Path::new(&aardvark_bin).exists() {
let path = Path::new(&config_dir).join("aardvark-dns");
if let Ok(path_string) = path.into_os_string().into_string() {
let aardvark_interface =
Aardvark::new(path_string, rootless, aardvark_bin, dns_port);
if let Err(err) = aardvark_interface
.modify_network_dns_servers(&self.network_name, &self.network_dns_servers)
{
return Err(NetavarkError::wrap(
"unable to modify network dns servers",
NetavarkError::Io(err),
));
}
} else {
return Err(NetavarkError::msg(
"Unable to parse aardvark config directory",
));
}
}

debug!("Network update complete");
Ok(())
}
}
56 changes: 56 additions & 0 deletions src/dns/aardvark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,62 @@ impl Aardvark {
Ok(())
}

// Modifies network dns_servers for a specific network and notifies aardvark-dns server
// with the change.
pub fn modify_network_dns_servers(
&self,
network_name: &str,
network_dns_servers: &Vec<String>,
) -> Result<()> {
let mut dns_servers_modified = false;
let path = Path::new(&self.config).join(network_name);
let file_content = fs::read_to_string(&path)?;

let mut file = File::create(&path)?;

//for line in lines {
for (idx, line) in file_content.split_terminator('\n').enumerate() {
if idx == 0 {
// If this is first line, we have to modify this
// first line has a format of `<BINDIP>... <NETWORK_DNSSERVERS>..`
// We will read the first line and get the first coloumn and
// override the second coloumn with new network dns servers.
let network_parts = line.split(' ').collect::<Vec<&str>>();
if network_parts.is_empty() {
return Err(std::io::Error::new(
std::io::ErrorKind::Other,
format!("invalid network configuration file: {}", path.display()),
));
}
let network_dns_servers_collected = if !network_dns_servers.is_empty() {
dns_servers_modified = true;
let dns_server_collected = network_dns_servers
.iter()
.map(|g| g.to_string())
.collect::<Vec<String>>()
.join(",");
format!(" {}", dns_server_collected)
} else {
"".to_string()
};
// Modify line to support new format
let content = format!("{}{}", network_parts[0], network_dns_servers_collected);
file.write_all(content.as_bytes())?;
} else {
file.write_all(line.as_bytes())?;
}
file.write_all(b"\n")?;
}

// If dns servers were updated notify the aardvark-dns server
// if refresh is needed.
if dns_servers_modified {
self.notify(false)?;
}

Ok(())
}

pub fn delete_from_netavark_entries(
&self,
network_options: &types::NetworkOptions,
Expand Down
4 changes: 4 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use clap::{Parser, Subcommand};

use netavark::commands::setup;
use netavark::commands::teardown;
use netavark::commands::update;
use netavark::commands::version;

#[derive(Parser, Debug)]
Expand All @@ -28,6 +29,8 @@ struct Opts {
enum SubCommand {
/// Configures the given network namespace with the given configuration.
Setup(setup::Setup),
/// Updates network dns servers for an already configured network.
Update(update::Update),
/// Undo any configuration applied via setup command.
Teardown(teardown::Teardown),
/// Display info about netavark.
Expand All @@ -47,6 +50,7 @@ fn main() {
let result = match opts.subcmd {
SubCommand::Setup(setup) => setup.exec(opts.file, config, aardvark_bin, rootless),
SubCommand::Teardown(teardown) => teardown.exec(opts.file, config, aardvark_bin, rootless),
SubCommand::Update(update) => update.exec(config, aardvark_bin, rootless),
SubCommand::Version(version) => version.exec(),
};

Expand Down
14 changes: 14 additions & 0 deletions src/network/core_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use netlink_packet_route::{
use nix::sched;
use sha2::{Digest, Sha512};
use std::collections::HashMap;
use std::env;
use std::fmt::Display;
use std::fs::File;
use std::io::{self, Error};
Expand All @@ -25,6 +26,19 @@ pub struct CoreUtils {
pub networkns: String,
}

pub fn get_netavark_dns_port() -> Result<u16, NetavarkError> {
match env::var("NETAVARK_DNS_PORT") {
Ok(port_string) => match port_string.parse() {
Ok(port) => Ok(port),
Err(e) => Err(NetavarkError::Message(format!(
"Invalid NETAVARK_DNS_PORT {}: {}",
port_string, e
))),
},
Err(_) => Ok(53),
}
}

pub fn parse_option<T>(
opts: &Option<HashMap<String, String>>,
name: &str,
Expand Down
41 changes: 41 additions & 0 deletions test/100-bridge-iptables.bats
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,47 @@ fw_driver=iptables
expected_rc=1 run_in_host_netns ip addr show podman0
}

@test "$fw_driver - bridge driver must generate config for aardvark with multiple custom dns server with network dns servers and perform update" {
# get a random port directly to avoid low ports e.g. 53 would not create iptables
dns_port=$((RANDOM+10000))

# hack to make aardvark-dns run when really root or when running as user with
# podman unshare --rootless-netns; since netavark runs aardvark with systemd-run
# it needs to know if it should use systemd user instance or not.
# iptables are still setup identically.
rootless=false
if [[ ! -e "/run/dbus/system_bus_socket" ]]; then
rootless=true
fi

mkdir -p "$NETAVARK_TMPDIR/config"

NETAVARK_DNS_PORT="$dns_port" run_netavark --file ${TESTSDIR}/testfiles/dualstack-bridge-network-container-dns-server.json \
--rootless "$rootless" --config "$NETAVARK_TMPDIR/config" \
setup $(get_container_netns_path)

# check aardvark config and running
run_helper cat "$NETAVARK_TMPDIR/config/aardvark-dns/podman1"
assert "${lines[0]}" =~ "10.89.3.1,fd10:88:a::1 127.0.0.1,3.3.3.3" "aardvark set to listen to all IPs"
assert "${lines[1]}" =~ "^[0-9a-f]{64} 10.89.3.2 fd10:88:a::2 somename 8.8.8.8,1.1.1.1$" "aardvark config's container"
assert "${#lines[@]}" = 2 "too many lines in aardvark config"

aardvark_pid=$(cat "$NETAVARK_TMPDIR/config/aardvark-dns/aardvark.pid")
assert "$ardvark_pid" =~ "[0-9]*" "aardvark pid not found"
run_helper ps "$aardvark_pid"
assert "${lines[1]}" =~ ".*aardvark-dns --config $NETAVARK_TMPDIR/config/aardvark-dns -p $dns_port run" "aardvark not running or bad options"

NETAVARK_DNS_PORT="$dns_port" run_netavark --file ${TESTSDIR}/testfiles/dualstack-bridge-network-container-dns-server.json \
--rootless "$rootless" --config "$NETAVARK_TMPDIR/config" \
update podman1 --network-dns-servers 8.8.8.8

# check aardvark config and running
run_helper cat "$NETAVARK_TMPDIR/config/aardvark-dns/podman1"
assert "${lines[0]}" =~ "10.89.3.1,fd10:88:a::1 8.8.8.8" "aardvark set to listen to all IPs"
assert "${lines[1]}" =~ "^[0-9a-f]{64} 10.89.3.2 fd10:88:a::2 somename 8.8.8.8,1.1.1.1$" "aardvark config's container"
assert "${#lines[@]}" = 2 "too many lines in aardvark config"
}

@test "$fw_driver - ipv6 bridge" {
run_netavark --file ${TESTSDIR}/testfiles/ipv6-bridge.json setup $(get_container_netns_path)
result="$output"
Expand Down

0 comments on commit f7186d3

Please sign in to comment.