Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
Signed-off-by: Simon LUCIDO <simon.lucido@etu.umontpellier.fr>
  • Loading branch information
lucido-simon committed Oct 30, 2023
1 parent bfaf69f commit c4d6489
Show file tree
Hide file tree
Showing 3 changed files with 180 additions and 60 deletions.
22 changes: 17 additions & 5 deletions initramfs/src/httpclient.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,26 @@
use std::collections::HashMap;

use anyhow::{anyhow, Result};
use reqwest::{Client, Response};

pub async fn run_get_request(url: &str, token: Option<&str>) -> Result<Response> {
let res = match token {
pub async fn run_get_request(
url: &str,
token: Option<&str>,
headers: HashMap<String, String>,
) -> Result<Response> {
let mut res = match token {
Some(token) => Client::new().get(url).bearer_auth(token),
None => Client::new().get(url),
};

for (key, value) in headers {
res = res.header(key, value);
}
.send()
.await
.map_err(|e| anyhow!(e).context(format!("Failed to run request to {}", url)))?;

let res = res
.send()
.await
.map_err(|e| anyhow!(e).context(format!("Failed to run request to {}", url)))?;

if !res.status().is_success() {
return Err(anyhow!(res.text().await.unwrap_or_default())
Expand Down
115 changes: 64 additions & 51 deletions initramfs/src/image.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
use std::{
collections::HashMap,
collections::{HashMap, HashSet},
fs::File,
io::{Cursor, Read},
};

use anyhow::{anyhow, Result};
use bytes::Bytes;
use cpio::{newc::Builder, write_cpio};
use cpio::{
newc::{trailer, Builder},
write_cpio,
};
use libflate::gzip::{Decoder, Encoder};
use log::debug;
use serde::Deserialize;
Expand Down Expand Up @@ -69,12 +72,13 @@ impl Image {
) -> Result<()> {
// Write the cpio to disk
let file_name = format!("initramfs-{}-{}.img", self.name.replace('/', "-"), self.tag);
let archive = Encoder::new(
let mut zip = Encoder::new(
File::create(file_name).map_err(|e| anyhow!(e).context("Failed to create file"))?,
)
.map_err(|e| anyhow!(e).context("Failed to create gzip encoder"))?;

let mut entries = HashMap::new();
// let mut entries = HashSet::new();
let mut ino = 1;

for layer in self.layers.clone() {
let mut archive = Archive::new(Decoder::new(layer.content)?);
Expand All @@ -92,15 +96,16 @@ impl Image {
.ok_or_else(|| anyhow!("Failed to convert path to string"))?
.to_string();

if entries.contains_key(&path) {
continue;
}
// if !entries.insert(path.clone()) {
// debug!("Skipping {} since it already exists", &path);
// continue;
// }

let mode = headers
.mode()
.map_err(|e| anyhow!(e).context("Failed to get mode of entry"))?;

let builder = Builder::new(&path)
zip = Builder::new(&path)
.uid(
headers
.uid()
Expand All @@ -113,16 +118,16 @@ impl Image {
.map_err(|e| anyhow!(e).context("Failed to get gid of entry"))?
as u32,
)
.mode(mode);
.mode(mode)
.ino(ino)
.write(zip, headers.size().unwrap_or_default() as u32)
.finish()?;

debug!("Adding {} to archive", &path);
std::io::copy(&mut entry, &mut zip)?;

let mut contents = Vec::new();
entry
.read_to_end(&mut contents)
.map_err(|e| anyhow!(e).context("Failed to read entry"))?;
ino += 1;

entries.insert(path, (builder, Cursor::new(contents)));
debug!("Added {} to archive", &path);
}
}

Expand All @@ -133,42 +138,50 @@ impl Image {
let mut agent_config_file = File::open(agent_config_path)
.map_err(|e| anyhow!(e).context("Failed to open agent config file"))?;

let mut init_content = Vec::new();
let mut agent_content = Vec::new();
let mut agent_config_content = Vec::new();

init_file.read_to_end(&mut init_content)?;
agent_file.read_to_end(&mut agent_content)?;
agent_config_file.read_to_end(&mut agent_config_content)?;

entries.insert(
"init".to_string(),
(Builder::new("init").mode(33277), Cursor::new(init_content)),
);
entries.insert(
"agent".to_string(),
(
Builder::new("agent").mode(33277),
Cursor::new(agent_content),
),
);
entries.insert(
"config.yaml".to_string(),
(
Builder::new("config.yaml").mode(33204),
Cursor::new(agent_config_content),
),
);

let test = entries
.drain()
.map(|(_, (builder, contents))| (builder, contents));
let archive =
write_cpio(test, archive).map_err(|e| anyhow!(e).context("Failed to write cpio"))?;
archive
.finish()
.into_result()
.map_err(|e| anyhow!(e).context("Failed to finish writing cpio"))?;
zip = Builder::new("init")
.mode(33277)
.write(zip, init_file.metadata().unwrap().len() as u32)
.finish()?;
std::io::copy(&mut init_file, &mut zip)?;

zip = Builder::new("agent")
.mode(33277)
.write(zip, agent_file.metadata().unwrap().len() as u32)
.finish()?;
std::io::copy(&mut agent_file, &mut zip)?;

zip = Builder::new("config.yaml")
.mode(33277)
.write(zip, agent_config_file.metadata().unwrap().len() as u32)
.finish()?;
std::io::copy(&mut agent_config_file, &mut zip)?;

// entries.insert(
// "agent".to_string(),
// (
// Builder::new("agent").mode(33277),
// Cursor::new(agent_content),
// ),
// );
// entries.insert(
// "config.yaml".to_string(),
// (
// Builder::new("config.yaml").mode(33204),
// Cursor::new(agent_config_content),
// ),
// );

// let test = entries
// .drain()
// .map(|(_, (builder, contents))| (builder, contents));
// let archive =
// write_cpio(test, zip).map_err(|e| anyhow!(e).context("Failed to write cpio"))?;
// archive
// .finish()
// .into_result()
// .map_err(|e| anyhow!(e).context("Failed to finish writing cpio"))?;
zip = trailer(zip)?;
zip.finish().into_result()?;

debug!("Successfully wrote cpio to disk");

Expand Down
103 changes: 99 additions & 4 deletions initramfs/src/registry.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::io::Cursor;
use std::{collections::HashMap, io::Cursor};

use anyhow::{anyhow, Result};
use log::{debug, info};
Expand All @@ -9,6 +9,48 @@ use crate::{
image::{Image, Layer, LayerMetadata},
};

#[derive(Deserialize, Debug)]
struct ManifestListV2Response {
manifests: Vec<ManifestV2ItemResponse>,
}

#[derive(Deserialize, Debug)]
struct ManifestV2Response {
schemaVersion: u32,
mediaType: String,
config: Config,
layers: Vec<LayerInfo>,
}

#[derive(Deserialize, Debug)]
pub struct Config {
mediaType: String,
size: u64,
digest: String,
}

#[derive(Deserialize, Debug)]
struct LayerInfo {
digest: String,
mediaType: String,
platform: Option<Platform>,
size: u64,
}

#[derive(Deserialize, Debug)]
struct ManifestV2ItemResponse {
digest: String,
mediaType: String,
platform: Option<Platform>,
size: u64,
}

#[derive(Deserialize, Debug)]
struct Platform {
architecture: String,
os: String,
}

#[derive(Deserialize)]
struct TokenResponse {
token: String,
Expand Down Expand Up @@ -40,6 +82,7 @@ impl Registry {
self.auth_url, image_name
),
None,
HashMap::new(),
)
.await?;

Expand All @@ -61,18 +104,69 @@ impl Registry {
image_name: &str,
image_tag: &str,
) -> Result<Vec<LayerMetadata>> {
debug!(
"Url: {}",
format!("{}/{}/manifests/{}", self.url, image_name, image_tag)
);

let mut headers = HashMap::new();
headers.insert(
"Accept".to_string(),
"application/vnd.docker.distribution.manifest.list.v2+json".to_string(),
);

let res = run_get_request(
&format!("{}/{}/manifests/{}", self.url, image_name, image_tag),
Some(token),
headers,
)
.await?;

// Extract the information about the layers from the manifest
let layers_metadata = res
.json::<ManifestResponse>()
.json::<ManifestListV2Response>()
.await
.map_err(|e| anyhow!(e).context("Failed to parse response"))?
.fsLayers;
.map_err(|e| anyhow!(e).context("Failed to parse response"))?;

let sub_manifest = layers_metadata
.manifests
.iter()
.find(|manifest| {
manifest
.platform
.as_ref()
.map(|platform| platform.os == "linux" && platform.architecture == "amd64")
.unwrap_or(false)
})
.map(|manifest| manifest.digest.clone())
.ok_or(anyhow!("No manifest found"))?;

let mut headers = HashMap::new();
headers.insert(
"Accept".to_string(),
"application/vnd.docker.distribution.manifest.v2+json".to_string(),
);

let res = run_get_request(
&format!("{}/{}/manifests/{}", self.url, image_name, sub_manifest),
Some(token),
headers,
)
.await?;

let res = res
.json::<ManifestV2Response>()
.await
.map_err(|e| anyhow!(e).context("Failed to parse response"))?;

let layers_metadata = res
.layers
.iter()
.map(|layer| layer.clone())
.map(|layer| LayerMetadata {
blobSum: layer.digest.clone(),
})
.collect();

debug!("Successfully got layers : {:?}", layers_metadata);

Expand All @@ -92,6 +186,7 @@ impl Registry {
self.url, image_name, layer_metadata.blobSum
),
Some(token),
HashMap::new(),
)
.await?;

Expand Down

0 comments on commit c4d6489

Please sign in to comment.