Merge pull request #704 from liubin/feature/689-setup-guest-DNS

agent: setup DNS for guest
This commit is contained in:
Peng Tao 2020-09-14 09:51:45 +08:00 committed by GitHub
commit 6e328c0599
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 144 additions and 0 deletions

View File

@ -3,8 +3,17 @@
// SPDX-License-Identifier: Apache-2.0
//
use anyhow::{anyhow, Context, Result};
use nix::mount::{self, MntFlags, MsFlags};
use protocols::types::{Interface, Route};
use slog::Logger;
use std::collections::HashMap;
use std::fs;
use crate::Sandbox;
const KATA_GUEST_SANDBOX_DNS_FILE: &str = "/run/kata-containers/sandbox/resolv.conf";
const GUEST_DNS_FILE: &str = "/etc/resolv.conf";
// Network fully describes a sandbox network with its interfaces, routes and dns
// related information.
@ -28,3 +37,116 @@ impl Network {
self.dns.push(dns);
}
}
pub fn setup_guest_dns(logger: Logger, dns_list: Vec<String>) -> Result<()> {
do_setup_guest_dns(
logger,
dns_list,
KATA_GUEST_SANDBOX_DNS_FILE,
GUEST_DNS_FILE,
)
}
fn do_setup_guest_dns(logger: Logger, dns_list: Vec<String>, src: &str, dst: &str) -> Result<()> {
let logger = logger.new(o!( "subsystem" => "network"));
if dns_list.len() == 0 {
info!(
logger,
"Did not set sandbox DNS as DNS not received as part of request."
);
return Ok(());
}
let attr = fs::metadata(dst);
if attr.is_err() {
// not exists or other errors that we could not use it anymore.
return Ok(());
}
if attr.unwrap().is_dir() {
return Err(anyhow!("{} is a directory", GUEST_DNS_FILE));
}
// write DNS to file
let content = dns_list
.iter()
.map(|x| x.trim())
.collect::<Vec<&str>>()
.join("\n");
fs::write(src, &content)?;
// bind mount to /etc/resolv.conf
mount::mount(Some(src), dst, Some("bind"), MsFlags::MS_BIND, None::<&str>)
.map_err(|err| anyhow!(err).context("failed to setup guest DNS"))?;
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use crate::skip_if_not_root;
use nix::mount;
use std::fs::File;
use std::io::Write;
use tempfile::tempdir;
#[test]
fn test_setup_guest_dns() {
skip_if_not_root!();
let drain = slog::Discard;
let logger = slog::Logger::root(drain, o!());
// create temp for /run/kata-containers/sandbox/resolv.conf
let src_dir = tempdir().expect("failed to create tmpdir");
let tmp = src_dir.path().join("resolv.conf");
let src_filename = tmp.to_str().expect("failed to get resolv file filename");
// create temp for /etc/resolv.conf
let dst_dir = tempdir().expect("failed to create tmpdir");
let tmp = dst_dir.path().join("resolv.conf");
let dst_filename = tmp.to_str().expect("failed to get resolv file filename");
{
let _file = File::create(dst_filename).unwrap();
}
// test DNS
let dns = vec![
"nameserver 1.2.3.4".to_string(),
"nameserver 5.6.7.8".to_string(),
];
// write to /run/kata-containers/sandbox/resolv.conf
let mut src_file =
File::create(src_filename).expect(&format!("failed to create file {:?}", src_filename));
let content = dns.join("\n");
src_file
.write_all(content.as_bytes())
.expect(&format!("failed to write file contents"));
// call do_setup_guest_dns
let result = do_setup_guest_dns(logger, dns.clone(), src_filename, dst_filename);
assert_eq!(
true,
result.is_ok(),
"result should be ok, but {:?}",
result
);
// get content of /etc/resolv.conf
let content = fs::read_to_string(dst_filename);
assert_eq!(true, content.is_ok());
let content = content.unwrap();
let expected_DNS: Vec<&str> = content.split('\n').collect();
// assert the data are the same as /run/kata-containers/sandbox/resolv.conf
assert_eq!(dns, expected_DNS);
// umount /etc/resolv.conf
let _ = mount::umount(dst_filename);
}
}

View File

@ -37,6 +37,8 @@ use crate::linux_abi::*;
use crate::metrics::get_metrics;
use crate::mount::{add_storages, remove_mounts, BareMount, STORAGEHANDLERLIST};
use crate::namespace::{NSTYPEIPC, NSTYPEPID, NSTYPEUTS};
use crate::network::setup_guest_dns;
use crate::network::Network;
use crate::random;
use crate::sandbox::Sandbox;
use crate::version::{AGENT_VERSION, API_VERSION};
@ -1066,6 +1068,7 @@ impl protocols::agent_ttrpc::AgentService for agentService {
) -> ttrpc::Result<Empty> {
Ok(Empty::new())
}
fn create_sandbox(
&self,
_ctx: &ttrpc::TtrpcContext,
@ -1131,8 +1134,27 @@ impl protocols::agent_ttrpc::AgentService for agentService {
}
};
match setup_guest_dns(sl!(), req.dns.to_vec()) {
Ok(dns_list) => {
let sandbox = self.sandbox.clone();
let mut s = sandbox.lock().unwrap();
let _ = req
.dns
.to_vec()
.iter()
.map(|dns| s.network.set_dns(dns.to_string()));
}
Err(e) => {
return Err(ttrpc::Error::RpcStatus(ttrpc::get_status(
ttrpc::Code::INTERNAL,
e.to_string(),
)))
}
};
Ok(Empty::new())
}
fn destroy_sandbox(
&self,
_ctx: &ttrpc::TtrpcContext,