Skip to content

Commit

Permalink
initial
Browse files Browse the repository at this point in the history
  • Loading branch information
daschr committed Sep 13, 2023
1 parent 3469fc9 commit c55009b
Show file tree
Hide file tree
Showing 4 changed files with 264 additions and 0 deletions.
11 changes: 11 additions & 0 deletions Cargo.toml
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"
110 changes: 110 additions & 0 deletions src/docker.rs
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)
}
}
98 changes: 98 additions & 0 deletions src/hosts.rs
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(())
}
}
45 changes: 45 additions & 0 deletions src/main.rs
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(())
}

0 comments on commit c55009b

Please sign in to comment.