Fetch an image from the Docker Registry
This commit is contained in:
parent
9f33ac46b2
commit
c44452648d
17
src/main.rs
17
src/main.rs
@ -1,18 +1,24 @@
|
|||||||
use std::{self, ffi::CString, path};
|
use std::{self, ffi::CString, path};
|
||||||
|
|
||||||
|
mod registry;
|
||||||
|
|
||||||
// Usage: your_docker.sh run <image> <command> <arg1> <arg2> ...
|
// Usage: your_docker.sh run <image> <command> <arg1> <arg2> ...
|
||||||
fn main() {
|
fn main() {
|
||||||
let args: Vec<_> = std::env::args().collect();
|
let args: Vec<_> = std::env::args().collect();
|
||||||
|
let image_name = &args[2];
|
||||||
let command = &args[3];
|
let command = &args[3];
|
||||||
let command_args = &args[4..];
|
let command_args = &args[4..];
|
||||||
|
|
||||||
let base = "/tmp/mydocker";
|
let base_path = std::env::temp_dir().join("mydocker");
|
||||||
let base_path = path::Path::new(base);
|
|
||||||
|
|
||||||
// prevent cryptic "no such file or directory" error inside chroot
|
// prevent cryptic "no such file or directory" error inside chroot
|
||||||
std::fs::create_dir_all(base_path.join("dev")).unwrap();
|
std::fs::create_dir_all(base_path.join("dev")).unwrap();
|
||||||
std::fs::File::create(base_path.join("dev/null")).unwrap();
|
std::fs::File::create(base_path.join("dev/null")).unwrap();
|
||||||
|
|
||||||
|
let image = registry::ImageIdentifier::from_string(image_name);
|
||||||
|
let mut reg = registry::Registry::default();
|
||||||
|
reg.pull(&image, base_path.to_str().unwrap());
|
||||||
|
|
||||||
// copy over binary into chroot
|
// copy over binary into chroot
|
||||||
let command_path = path::Path::new(command).strip_prefix("/").unwrap();
|
let command_path = path::Path::new(command).strip_prefix("/").unwrap();
|
||||||
std::fs::create_dir_all(base_path.join(command_path.parent().unwrap()))
|
std::fs::create_dir_all(base_path.join(command_path.parent().unwrap()))
|
||||||
@ -21,7 +27,7 @@ fn main() {
|
|||||||
.expect("Failed copying executed binary to chroot directory");
|
.expect("Failed copying executed binary to chroot directory");
|
||||||
|
|
||||||
// create and change into chroot
|
// create and change into chroot
|
||||||
let cbase_path = CString::new(base.to_owned()).unwrap();
|
let cbase_path = CString::new(base_path.to_str().unwrap().to_owned()).unwrap();
|
||||||
unsafe {
|
unsafe {
|
||||||
libc::chroot(cbase_path.as_ptr());
|
libc::chroot(cbase_path.as_ptr());
|
||||||
}
|
}
|
||||||
@ -43,8 +49,5 @@ fn main() {
|
|||||||
let std_err = std::str::from_utf8(&output.stderr).unwrap();
|
let std_err = std::str::from_utf8(&output.stderr).unwrap();
|
||||||
eprint!("{}", std_err);
|
eprint!("{}", std_err);
|
||||||
|
|
||||||
match output.status.code() {
|
std::process::exit(output.status.code().unwrap_or(1));
|
||||||
Some(code) => std::process::exit(code),
|
|
||||||
None => std::process::exit(1),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
92
src/registry.rs
Normal file
92
src/registry.rs
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
// TODO: Enable derive feature
|
||||||
|
|
||||||
|
pub struct Registry {
|
||||||
|
http_client: reqwest::blocking::Client,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Registry {
|
||||||
|
fn default() -> Self {
|
||||||
|
return Registry {
|
||||||
|
http_client: reqwest::blocking::Client::new(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Registry {
|
||||||
|
pub fn pull(&mut self, image: &ImageIdentifier, destination: &str) {
|
||||||
|
// Perform the little auth dance
|
||||||
|
let auth_url = format!("https://auth.docker.io/token?service=registry.docker.io&scope=repository%3A{}%2F{}%3Apull", image.author, image.name);
|
||||||
|
let auth: serde_json::Value = self
|
||||||
|
.http_client
|
||||||
|
.get(&auth_url)
|
||||||
|
.send()
|
||||||
|
.unwrap()
|
||||||
|
.json()
|
||||||
|
.unwrap();
|
||||||
|
let access_token = auth["token"].as_str().unwrap();
|
||||||
|
|
||||||
|
// Download the image manifest
|
||||||
|
let auth_header = format!("Bearer {}", access_token);
|
||||||
|
let image_url = format!(
|
||||||
|
"https://registry.hub.docker.com/v2/{}/{}/manifests/{}",
|
||||||
|
image.author, image.name, image.tag
|
||||||
|
);
|
||||||
|
let image_manifest: serde_json::Value = self
|
||||||
|
.http_client
|
||||||
|
.get(&image_url)
|
||||||
|
.header(reqwest::header::AUTHORIZATION, auth_header.to_owned())
|
||||||
|
.send()
|
||||||
|
.unwrap()
|
||||||
|
.json()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Download the image layers and extracts them
|
||||||
|
let temp_path = std::env::temp_dir();
|
||||||
|
for layer in image_manifest["fsLayers"].as_array().unwrap() {
|
||||||
|
let digest = layer["blobSum"].as_str().unwrap();
|
||||||
|
let blob_url = format!(
|
||||||
|
"https://registry.hub.docker.com/v2/{}/{}/blobs/{}",
|
||||||
|
image.author, image.name, digest
|
||||||
|
);
|
||||||
|
let blob = self
|
||||||
|
.http_client
|
||||||
|
.get(&blob_url)
|
||||||
|
.header(reqwest::header::AUTHORIZATION, auth_header.to_owned())
|
||||||
|
.send()
|
||||||
|
.unwrap()
|
||||||
|
.bytes()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let layer_path = temp_path.join(digest);
|
||||||
|
std::fs::write(layer_path.to_owned(), blob).unwrap();
|
||||||
|
|
||||||
|
// TODO: handle exit code of untar
|
||||||
|
std::process::Command::new("tar")
|
||||||
|
.args(["-xf", layer_path.to_str().unwrap(), "-C", destination])
|
||||||
|
.output()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
std::fs::remove_file(layer_path).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ImageIdentifier {
|
||||||
|
author: String,
|
||||||
|
name: String,
|
||||||
|
tag: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ImageIdentifier {
|
||||||
|
pub fn from_string(image: &String) -> Self {
|
||||||
|
let mut iter = image.rsplitn(2, ':');
|
||||||
|
let tag = iter.next().unwrap_or("latest").to_string();
|
||||||
|
let mut loc_iter = iter.next().unwrap().split('/').rev();
|
||||||
|
let name = loc_iter
|
||||||
|
.next()
|
||||||
|
.expect("No image name was supplied")
|
||||||
|
.to_string();
|
||||||
|
let author = loc_iter.next().unwrap_or("library").to_string();
|
||||||
|
return ImageIdentifier { author, name, tag };
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user