-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
264 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
[package] | ||
name = "containername_hosts" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
|
||
[dependencies] | ||
serde_json = "1.0.105" | ||
serde = {version = "1.0.183", features = ["derive"]} | ||
curl = "0.4.44" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
use std::str::from_utf8; | ||
|
||
use curl::easy::Easy; | ||
use curl::Error as CurlError; | ||
use serde::{Deserialize, Serialize}; | ||
|
||
use std::collections::HashMap; | ||
|
||
#[derive(Debug)] | ||
pub struct ContainerHostEntry { | ||
pub name: String, | ||
pub addr: String, | ||
} | ||
|
||
pub struct ContainerLister { | ||
docker_socket: String, | ||
} | ||
|
||
#[allow(non_snake_case)] | ||
#[derive(Deserialize, Serialize, Debug)] | ||
struct ContainerNetwork { | ||
IPAddress: String, | ||
Gateway: String, | ||
IPPrefixLen: u64, | ||
} | ||
|
||
#[allow(non_snake_case)] | ||
#[derive(Deserialize, Serialize, Debug)] | ||
struct ContainerNetworks { | ||
Networks: HashMap<String, ContainerNetwork>, | ||
} | ||
|
||
#[allow(non_snake_case)] | ||
#[derive(Deserialize, Serialize, Debug)] | ||
struct Container { | ||
Id: String, | ||
Names: Vec<String>, | ||
NetworkSettings: ContainerNetworks, | ||
} | ||
|
||
#[derive(Debug)] | ||
pub enum ListerError { | ||
CurlError(CurlError), | ||
ParsingError(serde_json::Error), | ||
} | ||
|
||
impl From<CurlError> for ListerError { | ||
fn from(v: CurlError) -> Self { | ||
ListerError::CurlError(v) | ||
} | ||
} | ||
|
||
impl From<serde_json::Error> for ListerError { | ||
fn from(v: serde_json::Error) -> Self { | ||
ListerError::ParsingError(v) | ||
} | ||
} | ||
|
||
impl ContainerLister { | ||
pub fn new(docker_socket: &str) -> Self { | ||
ContainerLister { | ||
docker_socket: docker_socket.into(), | ||
} | ||
} | ||
|
||
pub fn fetch(&self) -> Result<Vec<ContainerHostEntry>, ListerError> { | ||
let mut c = Easy::new(); | ||
c.unix_socket(&self.docker_socket)?; | ||
c.url("http:https://127.0.0.1/containers/json?all=true")?; | ||
|
||
let mut data = String::new(); | ||
{ | ||
let mut trans = c.transfer(); | ||
trans.write_function(|d| { | ||
if let Ok(s) = from_utf8(d) { | ||
data.push_str(s); | ||
} | ||
|
||
Ok(d.len()) | ||
})?; | ||
|
||
trans.perform()? | ||
} | ||
|
||
Ok(Self::get_containers(data.as_str())?) | ||
} | ||
|
||
fn get_containers(data: &str) -> Result<Vec<ContainerHostEntry>, serde_json::Error> { | ||
let containers: Vec<Container> = serde_json::from_str(data)?; | ||
|
||
let mut hostentries: Vec<ContainerHostEntry> = Vec::new(); | ||
|
||
for container in &containers { | ||
for name in &container.Names { | ||
for net in container.NetworkSettings.Networks.values() { | ||
if !net.IPAddress.is_empty() { | ||
hostentries.push(ContainerHostEntry { | ||
name: name.to_owned(), | ||
addr: net.IPAddress.clone(), | ||
}) | ||
} | ||
} | ||
} | ||
} | ||
|
||
println!("hostentries: {:?}", &hostentries); | ||
|
||
Ok(hostentries) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
use std::collections::HashMap; | ||
use std::fs::OpenOptions; | ||
use std::io::Error as IoError; | ||
use std::io::Write; | ||
use std::io::{BufRead, BufReader, BufWriter}; | ||
use std::path::{Path, PathBuf}; | ||
|
||
pub struct Hosts { | ||
file: PathBuf, | ||
pub sections: HashMap<Option<String>, Vec<String>>, | ||
} | ||
|
||
impl Hosts { | ||
pub fn new<P: Into<PathBuf> + AsRef<Path>>(path: P) -> Result<Self, IoError> { | ||
let path: PathBuf = path.into(); | ||
let fd = OpenOptions::new() | ||
.read(true) | ||
.write(true) | ||
.open(path.clone())?; | ||
let mut sections: HashMap<Option<String>, Vec<String>> = HashMap::new(); | ||
|
||
let mut current_section: Option<String> = None; | ||
let mut reader = BufReader::new(fd); | ||
let mut line = String::new(); | ||
|
||
let mut entries: Vec<String> = Vec::new(); | ||
|
||
while reader.read_line(&mut line)? != 0 { | ||
let tr_line = line.trim(); | ||
|
||
if tr_line.starts_with("#") | ||
&& tr_line | ||
.trim_start_matches(&['#', ' ']) | ||
.starts_with("SECTION") | ||
{ | ||
let new_section_name = match tr_line.split(' ').last() { | ||
Some(name) if name != "SECTION" => name, | ||
_ => continue, | ||
}; | ||
|
||
if entries.len() > 0 { | ||
sections.insert(current_section, entries.clone()); | ||
entries.clear(); | ||
} | ||
|
||
current_section = Some(String::from(new_section_name)); | ||
} else { | ||
entries.push(tr_line.to_string()); | ||
} | ||
|
||
line.clear(); | ||
} | ||
|
||
if entries.len() > 0 { | ||
sections.insert(current_section, entries); | ||
} | ||
|
||
Ok(Hosts { | ||
file: path, | ||
sections, | ||
}) | ||
} | ||
|
||
pub fn update_section<S: Into<String>>( | ||
&mut self, | ||
section_name: Option<S>, | ||
entries: Vec<String>, | ||
) { | ||
self.sections | ||
.insert(section_name.map(|v| v.into()), entries); | ||
} | ||
|
||
pub fn write(&mut self) -> Result<(), IoError> { | ||
let fd = OpenOptions::new().write(true).open(self.file.clone())?; | ||
let mut writer = BufWriter::new(fd); | ||
|
||
if let Some(entries) = self.sections.remove(&None) { | ||
for e in entries.iter() { | ||
writer.write_all(e.as_bytes())?; | ||
writer.write_all(&['\n' as u8])?; | ||
} | ||
} | ||
|
||
for (section, entries) in self.sections.iter() { | ||
let section = section.as_ref().unwrap(); | ||
writer.write_all(format!("# SECTION {}\n", section).as_bytes())?; | ||
|
||
for e in entries.iter() { | ||
writer.write_all(e.as_bytes())?; | ||
writer.write_all(&['\n' as u8])?; | ||
} | ||
} | ||
|
||
writer.flush()?; | ||
|
||
Ok(()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
use std::env; | ||
use std::io::Error as IoError; | ||
use std::path::Path; | ||
use std::process::exit; | ||
|
||
mod docker; | ||
mod hosts; | ||
use hosts::Hosts; | ||
|
||
const DOCKER_SOCKET: &str = "/var/run/docker.sock"; | ||
const HOSTS: &str = "/etc/hosts"; | ||
|
||
fn main() -> Result<(), IoError> { | ||
let lister = docker::ContainerLister::new(DOCKER_SOCKET); | ||
let container_entries: Vec<String> = match lister.fetch() { | ||
Ok(v) => v | ||
.iter() | ||
.map(|x| format!("{}\t{}", x.name, x.addr)) | ||
.collect(), | ||
Err(e) => { | ||
eprintln!("Could not fetch containers: {:?}", e); | ||
exit(1); | ||
} | ||
}; | ||
|
||
if container_entries.len() == 0 { | ||
exit(0); | ||
} | ||
|
||
let mut hosts = match Hosts::new(HOSTS) { | ||
Ok(v) => v, | ||
Err(e) => { | ||
eprintln!("Error: could not open hosts: {:?}", e); | ||
exit(1); | ||
} | ||
}; | ||
|
||
println!("sections: {:?}", hosts.sections); | ||
|
||
hosts.update_section(Some("DOCKER_CONTAINERS"), container_entries); | ||
|
||
hosts.write()?; | ||
|
||
Ok(()) | ||
} |