Skip to content

Commit 9cd2ebd

Browse files
committed
wip
1 parent 946f3b2 commit 9cd2ebd

1 file changed

Lines changed: 159 additions & 31 deletions

File tree

src/quardle/mod.rs

Lines changed: 159 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,21 @@
1-
use std::fs::{File, create_dir_all, remove_dir_all, metadata};
1+
use std::fs::{File, create_dir_all, remove_dir_all};
22
use flate2::Compression;
33
use flate2::write::GzEncoder;
44
use serde::{Deserialize, Serialize};
55
use serde_json;
6+
use std::process::Command;
67

78
/// Constances declarations
8-
const QUARDLE_BUILD_DIR: &str = "/tmp/quark/builds/";
9-
const QUARDLE_KERNEL: &str = "linux-config-x86_64";
10-
const QUARDLE_INITRD: &str = "quarkfs/";
9+
const QUARK_BUILD_DIR: &str = "/tmp/quark/builds/";
10+
const QUARK_CONFIG_DIR: &str = "/opt/quark/";
11+
12+
const QUARDLE_KERNEL: &str = "bzImage";
13+
const QUARDLE_INITRD: &str = "rootfs/";
1114
const QUARDLE_KERNEL_CMDLINE: &str = "/proc/cmdline";
1215

1316
/// Containers related errors
1417
#[derive(Debug, thiserror::Error)]
1518
pub enum Error {
16-
#[error("Error when building quardle")]
17-
Build(String),
18-
#[error("Unable to instanciate quardle")]
19-
New(String),
20-
#[error("Error when deleting quardle")]
21-
Delete(String),
2219
}
2320

2421
/// A common result type for our module.
@@ -47,11 +44,20 @@ impl Quardle {
4744
/// Build a quardle from instance variables
4845
/// If delete is true, delete the quardle after building
4946
pub fn build(&self, delete_after: Option<bool>) -> Result<()> {
50-
47+
// creating working directory
48+
create_dir_all(self.clone().get_work_dir()).unwrap();
49+
50+
self
51+
.setup()
52+
.add_kernel()
53+
.add_init_rd()
54+
.add_kaps();
55+
self.generate_config_file()?;
56+
5157
self.generate_archive()?;
5258

5359
if delete_after.unwrap_or(false) {
54-
self.delete()?;
60+
self.delete();
5561
}
5662

5763
Ok(())
@@ -61,28 +67,155 @@ impl Quardle {
6167
/// Temp files used to create quardle are created at /tmp/quark/builds/<quardle_name>/
6268
pub fn new(name: String, container_image_url: String, offline: bool) -> Option<Self> {
6369
let quardle = Quardle {name, container_image_url, offline};
64-
create_dir_all(quardle.clone().get_work_dir()).unwrap();
6570
Some(quardle)
6671
}
6772

6873
/// Delete all temporary files used to create quardle are created at /tmp/quark/builds/<quardle_name>/
69-
pub fn delete(&self) -> Result<()> {
74+
pub fn delete(&self) -> &Quardle {
7075
remove_dir_all(self.clone().get_work_dir()).unwrap();
71-
Ok(())
76+
self
7277
}
7378

7479
/// Return the path to the quardle working directory
7580
/// /tmp/quark/builds/<quardle_name>/
7681
/// Used to create temporary files
7782
fn get_work_dir(self) -> String {
78-
format!("{}{}/", QUARDLE_BUILD_DIR, self.name)
83+
format!("{}{}/", QUARK_BUILD_DIR, self.name)
84+
}
85+
86+
/// Setup default quark configuration
87+
/// Create a `quark` directory in /opt
88+
fn setup(&self) -> &Quardle {
89+
// Create the quark configuration directory
90+
if !std::path::Path::new(&format!("{}", QUARK_CONFIG_DIR)).exists() {
91+
println!("Quark configuration directory does not exist, creating it !");
92+
Command::new("mkdir")
93+
.arg("/opt/quark")
94+
.output()
95+
.expect("failed to setup quark");
96+
}
97+
98+
// Install kaps sources
99+
if !std::path::Path::new(&format!("{}kaps", QUARK_CONFIG_DIR)).exists() {
100+
println!("Kaps not found, installing it !");
101+
Command::new("git")
102+
.args(["clone", "https://github.com/virt-do/kaps.git"]) // Using https protocol because it seems not supporting ssh
103+
.current_dir(format!("{}", QUARK_CONFIG_DIR))
104+
.output()
105+
.expect("failed to fetch kaps");
106+
}
107+
108+
// Install a default kernel configuration file
109+
if !std::path::Path::new(&format!("{}linux-config-x86_64", QUARK_CONFIG_DIR)).exists() {
110+
println!("Kernel config file not found, installing it !");
111+
Command::new("curl")
112+
.arg("https://raw.githubusercontent.com/virt-do/lab/main/do-vmm/kernel/linux-config-x86_64")
113+
.arg("-O")
114+
.current_dir(format!("{}", QUARK_CONFIG_DIR))
115+
.output()
116+
.expect("failed to fetch kernel config file");
117+
}
118+
119+
// Install a script to build kernel
120+
if !std::path::Path::new(&format!("{}kernel", QUARK_CONFIG_DIR)).exists() {
121+
println!("Kernel not found, installing and building it !");
122+
Command::new("git")
123+
.arg("clone")
124+
.args(["--depth", "1"])
125+
.arg("https://github.com/cloud-hypervisor/linux.git") // Using https protocol because it seems not supporting ssh
126+
.args(["-b", "ch-5.14"])
127+
.arg("kernel")
128+
.current_dir(format!("{}", QUARK_CONFIG_DIR))
129+
.output()
130+
.expect("failed to download kernel builder");
131+
// Use our config file
132+
Command::new("cp")
133+
.arg(format!("{}linux-config-x86_64", QUARK_CONFIG_DIR))
134+
.arg(format!("{}kernel/.config", QUARK_CONFIG_DIR))
135+
.output()
136+
.expect("failed to copy kernel config");
137+
138+
// Building kernel binary
139+
// FIXME: It seems that the build process is not working properly, command is stopped during build process
140+
Command::new("make")
141+
.arg("bzImage")
142+
.args(["-j", "nproc"])
143+
.current_dir(format!("{}kernel", QUARK_CONFIG_DIR))
144+
.status() // Here we are using status because we have to wait the command to finish
145+
.expect("failed to build kernel binary");
146+
}
147+
148+
self
149+
}
150+
151+
/// Append kernel configuration
152+
/// Fetch automated script if isn't already installed, and use some bash script to build it
153+
fn add_kernel(&self) -> &Quardle {
154+
println!("Installing kernel binary !");
155+
Command::new("cp")
156+
.arg(format!("{}arch/x86/boot/bzImage", QUARK_CONFIG_DIR))
157+
.arg(format!("{}/", self.clone().get_work_dir()))
158+
.spawn()
159+
.expect("failed to copy kernel");
160+
self
161+
}
162+
163+
/// Append basic rootfs
164+
/// Fetch automated script if isn't already installed, and use some bash script to build it
165+
fn add_init_rd(&self) -> &Quardle {
166+
println!("Installing initRamFS");
167+
Command::new("curl")
168+
.arg("https://dl-cdn.alpinelinux.org/alpine/v3.14/releases/x86_64/alpine-minirootfs-3.14.2-x86_64.tar.gz")
169+
.arg("-O")
170+
.current_dir(self.clone().get_work_dir())
171+
.output()
172+
.expect("failed to download alpine image");
173+
Command::new("mkdir")
174+
.arg(QUARDLE_INITRD)
175+
.current_dir(self.clone().get_work_dir())
176+
.output()
177+
.expect("failed to create rootfs folder");
178+
Command::new("tar")
179+
.arg("-xf")
180+
.arg("alpine-minirootfs-3.14.2-x86_64.tar.gz")
181+
.args(["-C", QUARDLE_INITRD])
182+
.current_dir(self.clone().get_work_dir())
183+
.output()
184+
.expect("failed to untar alpine image");
185+
Command::new("rm")
186+
.arg("-f")
187+
.arg("alpine-minirootfs-3.14.2-x86_64.tar.gz")
188+
.current_dir(self.clone().get_work_dir())
189+
.output()
190+
.expect("failed to delete downloaded archive");
191+
Command::new("runc")
192+
.arg("spec")
193+
.arg("--rootless")
194+
.current_dir(self.clone().get_work_dir())
195+
.output()
196+
.expect("failed to generate runtime spec");
197+
self
79198
}
80199

81200
/// Append kaps binary to builded image
82201
/// Fetch kaps source code if isn't already installed, build it from source and copy it to the working directory
83-
// TODO: appends kaps binary at /opt/kaps/bin/kaps and set a ln -s /opt/kaps/bin/kaps /usr/bin/kaps
84-
fn append_kaps(&self) -> Result<()> {
85-
Ok(())
202+
fn add_kaps(&self) -> &Quardle {
203+
Command::new("cargo")
204+
.current_dir(format!("{}kaps", QUARK_CONFIG_DIR))
205+
.arg("build")
206+
.arg("--release")
207+
// .arg("--out-dir") //TODO: outdir is only available on nightly for now, should be used later
208+
// .arg(format!("{}/rootfs/usr/bin/kaps",self.clone().get_work_dir()))
209+
.output()
210+
.expect("failed to build kaps");
211+
212+
Command::new("cp")
213+
.arg(format!("{}kaps/target/release/kaps", QUARK_CONFIG_DIR))
214+
.arg(format!("{}/rootfs/usr/bin/kaps",self.clone().get_work_dir()))
215+
.output()
216+
.expect("failed to copy kaps");
217+
218+
self
86219
}
87220

88221
/// Generate the config file of the quardle
@@ -106,12 +239,13 @@ impl Quardle {
106239

107240
/// Create compressed archive from quardle files and result it at /out/<quardle_name>.qrk
108241
fn generate_archive(&self) -> Result<()> {
109-
let tar_gz = File::create(format!("out/{}.qrk",self.name)).unwrap();
110-
let enc = GzEncoder::new(tar_gz, Compression::default());
111-
let mut tar = tar::Builder::new(enc);
112-
self.generate_config_file()?;
113-
tar.append_dir_all(".", self.clone().get_work_dir()).unwrap();
114-
Ok(())
242+
let tar_gz = File::create(format!("out/{}.qrk",self.name)).unwrap();
243+
let enc = GzEncoder::new(tar_gz, Compression::default());
244+
let mut tar = tar::Builder::new(enc);
245+
246+
// tar.append_dir_all("./", self.clone().get_work_dir()).unwrap();
247+
tar.finish().unwrap();
248+
Ok(())
115249
}
116250
}
117251

@@ -126,12 +260,6 @@ mod tests {
126260
assert_eq!(quardle.as_ref().unwrap().container_image_url, "container1");
127261
}
128262

129-
#[test]
130-
fn quardle_delete() {
131-
let quardle = Quardle::new("test".to_string(), "test".to_string(), false);
132-
assert_eq!(quardle.unwrap().delete().unwrap(), ());
133-
}
134-
135263
#[test]
136264
fn quardle_get_work_dir() {
137265
let quardle = Quardle::new("this-should-be-a-directory".to_string(), "my-container".to_string(), false);

0 commit comments

Comments
 (0)