lithos 0.18.4

A containerization framework for linux
Documentation
extern crate libc;
extern crate nix;
extern crate env_logger;
extern crate regex;
extern crate argparse;
extern crate quire;
#[macro_use] extern crate log;
extern crate lithos;


use std::env;
use std::io::{stderr, Read, Write};
use std::process::exit;
use std::path::{Path, PathBuf};
use std::str::FromStr;
use std::fs::{File};
use std::fs::{copy, rename};
use std::process::{Command, Stdio};

use argparse::{ArgumentParser, Parse, StoreTrue, Print};
use quire::{parse_config, Options};
use nix::sys::signal::{SIGQUIT, kill};
use nix::unistd::Pid;

use lithos::master_config::MasterConfig;
use lithos::sandbox_config::SandboxConfig;


fn switch_config(master_cfg: &Path, sandbox_name: String, config_file: &Path)
    -> Result<(), String>
{
    match Command::new(env::current_exe().unwrap()
                       .parent().unwrap().join("lithos_check"))
        .stdin(Stdio::inherit())
        .stdout(Stdio::inherit())
        .stderr(Stdio::inherit())
        .arg("--config")
        .arg(&master_cfg)
        .arg("--sandbox")
        .arg(&sandbox_name)
        .arg("--alternate-config")
        .arg(&config_file)
        .output()
    {
        Ok(ref po) if po.status.code() == Some(0) => { }
        Ok(ref po) => {
            return Err(format!(
                "Configuration check failed with exit status: {}",
                po.status));
        }
        Err(e) => {
            return Err(format!("Can't check configuration: {}", e));
        }
    }
    info!("Checked. Proceeding");

    let master: MasterConfig = match parse_config(&master_cfg,
        &MasterConfig::validator(), &Options::default())
    {
        Ok(cfg) => cfg,
        Err(e) => {
            return Err(format!("Can't parse master config: {}", e));
        }
    };
    let sandbox_fn = master_cfg.parent().unwrap()
        .join(&master.sandboxes_dir)
        .join(&(sandbox_name.clone() + ".yaml"));
    let sandbox: SandboxConfig = match parse_config(&sandbox_fn,
        &SandboxConfig::validator(), &Options::default())
    {
        Ok(cfg) => cfg,
        Err(e) => {
            return Err(format!("Can't parse sandbox config: {}", e));
        }
    };

    let target_fn = master_cfg.parent().unwrap()
        .join(&master.processes_dir)
        .join(sandbox.config_file.as_ref().unwrap_or(
            &PathBuf::from(&(sandbox_name.clone() + ".yaml"))));
    debug!("Target filename {:?}", target_fn);
    let tmp_filename = target_fn.with_file_name(
        &format!(".tmp.{}", sandbox_name));
    try!(copy(&config_file, &tmp_filename)
        .map_err(|e| format!("Error copying: {}", e)));
    try!(rename(&tmp_filename, &target_fn)
        .map_err(|e| format!("Error replacing file: {}", e)));

    info!("Done. Sending SIGQUIT to lithos_tree");
    let pid_file = master.runtime_dir.join("master.pid");
    let mut buf = String::with_capacity(50);
    let read_pid = File::open(&pid_file)
            .and_then(|mut f| f.read_to_string(&mut buf))
            .ok()
            .and_then(|_| FromStr::from_str(buf[..].trim()).ok())
            .map(Pid::from_raw);
    match read_pid {
        Some(pid) if kill(pid, None).is_ok() => {
            kill(pid, SIGQUIT)
            .map_err(|e| error!("Error sending QUIT to master: {:?}", e)).ok();
        }
        Some(pid) => {
            warn!("Process with pid {} is not running...", pid);
        }
        None => {
            warn!("Can't read pid file {}. Probably daemon is not running.",
                pid_file.display());
        }
    };

    return Ok(());
}


fn main() {
    if env::var("RUST_LOG").is_err() {
        env::set_var("RUST_LOG", "warn");
    }
    env_logger::init();

    let mut master_config = PathBuf::from("/etc/lithos/master.yaml");
    let mut verbose = false;
    let mut config_file = PathBuf::from("");
    let mut sandbox_name = "".to_string();
    {
        let mut ap = ArgumentParser::new();
        ap.set_description("Checks if lithos configuration is ok");
        ap.refer(&mut master_config)
          .add_option(&["--master"], Parse,
            "Name of the master configuration file \
                (default /etc/lithos/master.yaml)")
          .metavar("FILE");
        ap.refer(&mut verbose)
          .add_option(&["-v", "--verbose"], StoreTrue,
            "Verbose configuration");
        ap.refer(&mut sandbox_name)
          .add_argument("sandbox", Parse,
            "Name of the sandbox which configuration will be switched for")
          .required()
          .metavar("NAME");
        ap.refer(&mut config_file)
          .add_argument("new_config", Parse, "
            Name of the process configuration file for this sandbox to switch
            to. The file is copied over current config after configuration is
            validated and just before sending a signal to lithos_tree.")
          .metavar("FILE")
          .required();
        ap.add_option(&["--version"],
            Print(env!("CARGO_PKG_VERSION").to_string()),
            "Show version");
        match ap.parse_args() {
            Ok(()) => {}
            Err(x) => {
                exit(x);
            }
        }
    }
    match switch_config(&master_config, sandbox_name, &config_file)
    {
        Ok(()) => {
            exit(0);
        }
        Err(e) => {
            write!(&mut stderr(), "Fatal error: {}\n", e).unwrap();
            exit(1);
        }
    }
}