Add Support for extract and setup-secondary meta commands

This commit is contained in:
Sarah Jamie Lewis 2023-01-18 14:45:48 -08:00
parent 2e64438fed
commit dd8bf334ae
2 changed files with 154 additions and 31 deletions

76
rustfmt.toml Normal file
View File

@ -0,0 +1,76 @@
max_width = 200
hard_tabs = false
tab_spaces = 4
newline_style = "Auto"
indent_style = "Block"
use_small_heuristics = "Default"
fn_call_width = 60
attr_fn_like_width = 70
struct_lit_width = 18
struct_variant_width = 35
array_width = 60
chain_width = 60
single_line_if_else_max_width = 50
wrap_comments = false
format_code_in_doc_comments = false
doc_comment_code_block_width = 100
comment_width = 80
normalize_comments = false
normalize_doc_attributes = false
format_strings = false
format_macro_matchers = false
format_macro_bodies = true
hex_literal_case = "Preserve"
empty_item_single_line = true
struct_lit_single_line = true
fn_single_line = false
where_single_line = false
imports_indent = "Block"
imports_layout = "Mixed"
imports_granularity = "Preserve"
group_imports = "Preserve"
reorder_imports = true
reorder_modules = true
reorder_impl_items = false
type_punctuation_density = "Wide"
space_before_colon = false
space_after_colon = true
spaces_around_ranges = false
binop_separator = "Front"
remove_nested_parens = true
combine_control_expr = true
short_array_element_width_threshold = 10
overflow_delimited_expr = false
struct_field_align_threshold = 0
enum_discrim_align_threshold = 0
match_arm_blocks = true
match_arm_leading_pipes = "Never"
force_multiline_blocks = false
fn_args_layout = "Tall"
brace_style = "SameLineWhere"
control_brace_style = "AlwaysSameLine"
trailing_semicolon = true
trailing_comma = "Vertical"
match_block_trailing_comma = false
blank_lines_upper_bound = 1
blank_lines_lower_bound = 0
edition = "2015"
version = "One"
inline_attribute_width = 0
format_generated_files = true
merge_derives = true
use_try_shorthand = false
use_field_init_shorthand = false
force_explicit_abi = true
condense_wildcard_suffixes = false
color = "Auto"
required_version = "1.5.1"
unstable_features = false
disable_all_formatting = false
skip_children = false
hide_parse_errors = false
error_on_line_overflow = false
error_on_unformatted = false
ignore = []
emit_mode = "Files"
make_backup = false

View File

@ -1,9 +1,10 @@
use std::fs::{remove_file, File};
use std::io::{BufRead, Read, Write};
use std::net::TcpListener;
use std::path::Path;
use std::process::{exit, Child, Command, Stdio};
use std::sync::{Arc, Mutex};
use std::thread::sleep;
use std::thread::{sleep, spawn};
use std::time::Duration;
use std::{fs, thread};
@ -62,6 +63,8 @@ impl QemuProcess {
format!("if=virtio,format=qcow2,file={}", path).as_str(),
"-drive",
"if=virtio,format=qcow2,file=vd.img",
"-qmp",
"tcp:localhost:4444,server,wait=off",
])
.stdin(Stdio::piped())
.stdout(Stdio::piped())
@ -108,8 +111,7 @@ impl QemuProcess {
loop {
{
let stdout = self.stdout.lock().unwrap();
let tbd =
String::from_utf8(stdout.as_slice()[self.len..stdout.len()].to_vec()).unwrap();
let tbd = String::from_utf8(stdout.as_slice()[self.len..stdout.len()].to_vec()).unwrap();
let parts: Vec<String> = tbd.split("\n").map(|x| String::from(x)).collect();
let last = &parts[parts.len() - 1];
if last.contains("root@debian:") && last.ends_with("# ") {
@ -155,6 +157,35 @@ impl QemuProcess {
print!("{} ", cmd);
}
pub fn extract(&mut self, file_to_extract: &str) {
let listener = TcpListener::bind("0.0.0.0:13087");
match listener {
Ok(socket) => {
let file_to_extract_clone = String::from(file_to_extract);
let handle = spawn(move || {
println!("setting up listen socket to extract file from guest network");
let conn = socket.accept();
match conn {
Ok((mut conn, _addr)) => {
let mut file = vec![];
conn.read_to_end(&mut file)
.expect("could not read contents of file");
fs::write(file_to_extract_clone.as_str(), file).expect("could not write extracted file to ");
}
Err(_) => {}
}
});
sleep(Duration::from_secs(1));
self.execute_command(format!("nc -w 3 10.0.2.2 13087 < {}", file_to_extract).as_str());
self.read_until_shell(false);
handle.join().expect("could not join networking thread");
}
Err(err) => {
println!("unable to listen to guest network...{}", err)
}
}
}
pub fn close(&mut self) {
self.child.kill().expect("could not kill qemu process");
}
@ -171,7 +202,6 @@ where
}
fn main() {
let args: Vec<String> = std::env::args().collect();
if args.len() != 3 {
println!("usage: repliqate <cloud-image.qcow2> <build script>");
@ -179,20 +209,15 @@ fn main() {
}
let cloud_image = &args[1];
let build_script = &args[2];
let inuse_cloud_image = format!("inuse-{}", cloud_image);
let inuse_cloud_image = format!("inuse-{}", cloud_image);
let _ = remove_file("vd.img");
fs::copy(
cloud_image.as_str(),
inuse_cloud_image.as_str(),
)
.expect("copying of clean image failed...");
fs::copy(cloud_image.as_str(), inuse_cloud_image.as_str()).expect("copying of clean image failed...");
Command::new("qemu-img")
.args(["create", "-f", "qcow2", "vd.img", "30G"])
.output()
.expect("error creating secondary harddisk image...");
let mut qemu_process = QemuProcess::new(inuse_cloud_image.as_str());
qemu_process.wait_for_shell();
@ -207,7 +232,7 @@ fn main() {
if line.trim().starts_with("#") {
// comment - skip
continue
continue;
}
if line.trim().starts_with("@%") {
@ -220,27 +245,49 @@ fn main() {
let parts: Vec<&str> = command.split(" ").collect();
if parts[0] == "preserve" {
purge = false;
println!("preserve metacommand activated. Virtual Disk Images will not be purged at end of run")
} else if parts[0] == "check" {
if parts.len() != 3 {
println!("check metacommand needs 2 arguments: check file hash")
match parts[0] {
"preserve" => {
purge = false;
println!("preserve metacommand activated. Virtual Disk Images will not be purged at end of run")
}
// maybe we need to sleep to let the slow...disk update...
sleep(Duration::from_secs(1));
qemu_process
.execute_command(format!("sha512sum {}", parts[1].trim()).as_str());
"setup-secondary" => {
qemu_process.execute_command("mkfs -t ext4 /dev/vdb");
qemu_process.read_until_shell(false);
qemu_process.execute_command(" mkdir /mount");
qemu_process.read_until_shell(false);
qemu_process.execute_command("mount -t auto /dev/vdb /mount");
qemu_process.read_until_shell(false);
}
"extract" => {
if parts.len() >= 2 {
qemu_process.extract(parts[1]);
} else {
println!("@!extract requires file parameter");
break;
}
}
"check" => {
if parts.len() != 3 {
println!("check metacommand needs 2 arguments: check file hash")
}
// maybe we need to sleep to let the slow...disk update...
sleep(Duration::from_secs(1));
qemu_process.execute_command(format!("sha512sum {}", parts[1].trim()).as_str());
let sha512result = qemu_process.read_until_shell(false);
println!("{:?}", sha512result);
if sha512result[0].starts_with(parts[2]) {
println!("confirmed build hash of {}", parts[1])
} else {
println!(
"check hashes do not match {}. {} != {}",
parts[1], parts[2], sha512result[0]
);
let sha512result = qemu_process.read_until_shell(false);
println!("{:?}", sha512result);
if sha512result[0].starts_with(parts[2]) {
println!("confirmed build hash of {}", parts[1])
} else {
println!(
"check hashes do not match {}. {} != {}",
parts[1], parts[2], sha512result[0]
);
break;
}
}
x => {
println!("unknown metacommand {}", x);
break;
}
}