diff --git a/Cargo.lock b/Cargo.lock index feffed10..c584398e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -189,6 +189,7 @@ dependencies = [ "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "quicli 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", "serde_yaml 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -217,6 +218,11 @@ name = "fuchsia-zircon-sys" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "gcc" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "globset" version = "0.4.1" @@ -350,6 +356,15 @@ dependencies = [ "proc-macro2 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rand" version = "0.4.2" @@ -422,11 +437,28 @@ dependencies = [ "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rust-crypto" +version = "0.2.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rustc-demangle" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "rustc-serialize" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "same-file" version = "1.0.4" @@ -565,6 +597,16 @@ dependencies = [ "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "time" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ucd-util" version = "0.1.1" @@ -690,6 +732,7 @@ dependencies = [ "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" +"checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" "checksum globset 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8e49edbcc9c7fc5beb8c0a54e7319ff8bed353a2b55e85811c6281188c2a6c84" "checksum globwalk 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce5d04da8cf35b507b2cbec92bbf2d5085292d07cd87637994fd437fe1617bbb" "checksum humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0484fda3e7007f2a4a0d9c3a703ca38c71c54c55602ce4660c419fd32e188c9e" @@ -706,6 +749,7 @@ dependencies = [ "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" "checksum quicli 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9e8539e98d5a5e3cb0398aedac3e9642ead7d3047a459893526710cb5ad86f6c" "checksum quote 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b71f9f575d55555aa9c06188be9d4e2bfc83ed02537948ac0d520c24d0419f1a" +"checksum rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" "checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5" "checksum rayon 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "df7a791f788cb4c516f0e091301a29c2b71ef680db5e644a7d68835c8ae6dbfa" "checksum rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b055d1e92aba6877574d8fe604a63c8b5df60f60e5982bf7ccbb1338ea527356" @@ -714,7 +758,9 @@ dependencies = [ "checksum regex 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5bbbea44c5490a1e84357ff28b7d518b4619a159fed5d25f6c1de2d19cc42814" "checksum regex-syntax 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "747ba3b235651f6e2f67dfa8bcdcd073ddb7c243cb21c442fc12395dfcac212d" "checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" +"checksum rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a" "checksum rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "bcfe5b13211b4d78e5c2cadfebd7769197d95c639c35a50057eb4c05de811395" +"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" "checksum same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" "checksum serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)" = "0c3adf19c07af6d186d91dae8927b83b0553d07ca56cbf7f2f32560455c91920" @@ -731,6 +777,7 @@ dependencies = [ "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" "checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6" "checksum thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279ef31c19ededf577bfd12dfae728040a21f635b06a24cd670ff510edd38963" +"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" "checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d" "checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" diff --git a/Cargo.toml b/Cargo.toml index 3fbdec3b..ca0e80d7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ serde_yaml = "0.7" structopt = "0.2" uuid = { version = "0.6", features = ["v4"] } yaml-rust = "0.4.3" +rust-crypto = "^0.2" [dev-dependencies] tempdir = "0.3.7" diff --git a/src/config.rs b/src/config.rs index 20a48958..66b340f7 100644 --- a/src/config.rs +++ b/src/config.rs @@ -34,8 +34,8 @@ impl Shell { #[derive(Debug, PartialEq, Serialize, Deserialize)] pub(crate) struct Volume { #[serde(default = "default_to_false")] - shared: bool, - mount: path::PathBuf, + pub(crate) shared: bool, + pub(crate) mount: path::PathBuf, } #[derive(Debug, PartialEq, Serialize, Deserialize)] diff --git a/src/environment.rs b/src/environment.rs index 5c6c1847..3147477c 100644 --- a/src/environment.rs +++ b/src/environment.rs @@ -12,6 +12,7 @@ pub struct Environment { pub floki_root: path::PathBuf, pub config_file: path::PathBuf, pub ssh_agent_socket: Option, + pub floki_workspace: path::PathBuf, } impl Environment { @@ -24,6 +25,7 @@ impl Environment { floki_root: floki_root, config_file: config_path, ssh_agent_socket: get_ssh_agent_socket_path(), + floki_workspace: get_floki_work_path()?, }) } } @@ -89,6 +91,14 @@ fn resolve_floki_root_and_config( } } +/// Resolve a directory for floki to use for user-global file (caches etc) +fn get_floki_work_path() -> Result { + let root: path::PathBuf = env::var("HOME") + .unwrap_or(format!("/tmp/{}/", get_user_details()?.0)) + .into(); + Ok(root.join(".floki")) +} + #[cfg(test)] mod test { use super::*; diff --git a/src/interpret.rs b/src/interpret.rs index 2fbb76dc..0d48d450 100644 --- a/src/interpret.rs +++ b/src/interpret.rs @@ -4,6 +4,7 @@ use crate::config::FlokiConfig; use crate::dind::Dind; use crate::environment::Environment; use crate::errors; +use crate::volumes::resolve_volume_mounts; use failure::Error; use std::path; @@ -14,6 +15,13 @@ pub(crate) fn run_container( config: &FlokiConfig, command: &str, ) -> Result<(), Error> { + let volumes = resolve_volume_mounts( + &environ.floki_root, + &environ.floki_workspace, + &config.volumes, + ); + debug!("Resolved volume mounts: {:?}", volumes); + let (mut cmd, mut dind) = build_basic_command(&environ.floki_root, &config)?; cmd = configure_dind(cmd, &config, &mut dind)?; diff --git a/src/main.rs b/src/main.rs index 59e9213f..9247c1d6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,6 +13,7 @@ mod errors; mod image; mod interpret; mod verify; +mod volumes; use cli::{Cli, Subcommand}; use config::FlokiConfig; diff --git a/src/volumes.rs b/src/volumes.rs new file mode 100644 index 00000000..7a0581c8 --- /dev/null +++ b/src/volumes.rs @@ -0,0 +1,124 @@ +use std::collections::BTreeMap; +use std::path; + +use crypto::digest::Digest; +use crypto::sha2::Sha256; + +use crate::config::Volume; + +pub(crate) fn resolve_volume_mounts( + floki_root: &path::PathBuf, + work_path: &path::PathBuf, + volumes: &BTreeMap, +) -> Vec<(path::PathBuf, path::PathBuf)> { + volumes + .iter() + .map(|(name, volume)| { + ( + cache_path(work_path, floki_root, name, volume), + volume.mount.clone(), + ) + }) + .collect() +} + +fn cache_path( + work_path: &path::PathBuf, + floki_root: &path::PathBuf, + name: &str, + config: &Volume, +) -> path::PathBuf { + let folder = prefix_cache(config.shared, floki_root) + name; + work_path.join(".cache/").join::(folder) +} + +fn prefix_cache(shared: bool, floki_root: &path::PathBuf) -> String { + if shared { + "".into() + } else { + hash_path(floki_root) + "-" + } +} + +fn hash_path(path: &path::PathBuf) -> String { + let mut hasher = Sha256::new(); + hasher.input_str(&path.as_os_str().to_string_lossy()); + hasher.result_str() +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_shared_cache_path_is_shared_across_flokis() { + let cache_1 = cache_path( + &"work_path".into(), + &"/floki/root/1/".into(), + "cache", + &Volume { + shared: true, + mount: "/".into(), + }, + ); + let cache_2 = cache_path( + &"work_path".into(), + &"/floki/root/2/".into(), + "cache", + &Volume { + shared: true, + mount: "/".into(), + }, + ); + + assert_eq!(cache_1, cache_2); + } + + #[test] + fn test_local_cache_path_is_not_shared_across_flokis() { + let cache_1 = cache_path( + &"work_path".into(), + &"/floki/root/1/".into(), + "cache", + &Volume { + shared: false, + mount: "/".into(), + }, + ); + let cache_2 = cache_path( + &"work_path".into(), + &"/floki/root/2/".into(), + "cache", + &Volume { + shared: false, + mount: "/".into(), + }, + ); + + assert_ne!(cache_1, cache_2); + } + + #[test] + fn test_local_and_shared_caches_dont_collide() { + let cache_shared = cache_path( + &"work_path".into(), + &"/floki/root/1/".into(), + "cache", + &Volume { + shared: true, + mount: "/".into(), + }, + ); + let cache_local = cache_path( + &"work_path".into(), + &"/floki/root/1/".into(), + "cache", + &Volume { + shared: false, + mount: "/".into(), + }, + ); + + assert_ne!(cache_shared, cache_local); + } +}