Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

hil: initial commit #97

Merged
merged 4 commits into from
May 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 127 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ members = [
"deps-tests",
"endpoints",
"header-parsing",
"hil",
"mcu-util",
"orb-attest",
"orb-backend-state",
Expand Down
27 changes: 27 additions & 0 deletions hil/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
[package]
name = "orb-hil"
version = "0.0.0"
description = "Everything related to hardware-in-loop"
authors = ["Ryan Butler <[email protected]>"]
publish = false

edition.workspace = true
license.workspace = true
repository.workspace = true
rust-version.workspace = true

[dependencies]
camino = "1.1.6"
clap = { version = "4", features = ["derive"] }
cmd_lib = "1.9.3"
color-eyre = "0.6"
orb-build-info.path = "../build-info"
orb-security-utils = { path = "../security-utils", features = ["reqwest"] }
reqwest = { version = "0.11", default-features = false, features = ["rustls-tls"] }
tempfile = "3"
tokio = { version = "1", default-features = false, features = ["macros"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }

[build-dependencies]
orb-build-info = { path = "../build-info", features = ["build-script"] }
1 change: 1 addition & 0 deletions hil/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# orb-hil
3 changes: 3 additions & 0 deletions hil/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fn main() {
orb_build_info::initialize().expect("failed to initialize build info")
}
80 changes: 80 additions & 0 deletions hil/src/download_s3.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
use camino::Utf8Path;
use cmd_lib::run_cmd;
use color_eyre::{
eyre::{ensure, ContextCompat, WrapErr},
Result, Section,
};

pub async fn download_url(url: &str, out_path: &Utf8Path) -> Result<()> {
let parent_dir = out_path
.parent()
.expect("please provide the path to a file");
ensure!(
parent_dir.try_exists().unwrap_or(false),
"parent directory {parent_dir} doesn't exist"
);
let out_path_copy = out_path.to_owned();
let url_copy = url.to_owned();
tokio::task::spawn_blocking(move || {
download_using_awscli(&url_copy, &out_path_copy)
})
.await
.wrap_err("task panicked")?
}

fn download_using_awscli(url: &str, out_path: &Utf8Path) -> Result<()> {
let result = run_cmd! {
info downloading $url to $out_path;
aws s3 cp $url $out_path;
info finished download!;
};
result
.wrap_err("failed to call aws cli")
.with_note(|| format!("url was {url}"))
.with_note(|| format!("out_path was {out_path}"))
.with_suggestion(|| "Are the AWS url and your credentials valid?")
}

/// Calculates the filename based on the s3 url.
pub fn parse_filename(url: &str) -> Result<String> {
let expected_prefix = "s3://worldcoin-orb-update-packages-stage/worldcoin/orb-os/";
let path = url
.strip_prefix(expected_prefix)
.wrap_err_with(|| format!("missing url prefix of {expected_prefix}"))?;
let splits: Vec<_> = path.split('/').collect();
ensure!(
splits.len() == 3,
"invalid number of '/' delineated segments in the url"
);
ensure!(
splits[2].contains(".tar."),
"it doesn't look like this url ends in a tarball"
);
Ok(format!("{}-{}", splits[0], splits[2]))
}
#[cfg(test)]
mod test {
use super::*;

#[test]
fn test_parse() -> color_eyre::Result<()> {
let examples = [
(
"s3://worldcoin-orb-update-packages-stage/worldcoin/orb-os/2024-05-07-heads-main-0-g4b8aae5/rts/rts-dev.tar.zst",
"2024-05-07-heads-main-0-g4b8aae5-rts-dev.tar.zst"
),
(
"s3://worldcoin-orb-update-packages-stage/worldcoin/orb-os/2024-05-08-remotes-pull-386-merge-0-geea20f1/rts/rts-prod.tar.zst",
"2024-05-08-remotes-pull-386-merge-0-geea20f1-rts-prod.tar.zst"
),
(
"s3://worldcoin-orb-update-packages-stage/worldcoin/orb-os/2024-05-08-tags-release-5.0.39-0-ga12b3d7/rts/rts-dev.tar.zst",
"2024-05-08-tags-release-5.0.39-0-ga12b3d7-rts-dev.tar.zst"
),
];
for (url, expected_filename) in examples {
assert_eq!(parse_filename(url)?, expected_filename);
}
Ok(())
}
}
77 changes: 77 additions & 0 deletions hil/src/flash.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
use std::path::Path;

use camino::Utf8Path;
use cmd_lib::run_cmd;
use color_eyre::{
eyre::{ensure, WrapErr},
Result, Section,
};
use tempfile::TempDir;

pub async fn flash(variant: FlashVariant, path_to_rts_tar: &Utf8Path) -> Result<()> {
let path_to_rts = path_to_rts_tar.to_owned();
tokio::task::spawn_blocking(move || {
let tmp_dir = extract(&path_to_rts)?;
println!("{tmp_dir:?}");
flash_cmd(variant, tmp_dir.path())?;
Ok(())
})
.await
.wrap_err("task panicked")?
}

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum FlashVariant {
Fast,
Regular,
}

impl FlashVariant {
fn file_name(&self) -> &'static str {
match self {
FlashVariant::Fast => "fastflashcmd.txt",
FlashVariant::Regular => "flashcmd.txt",
}
}
}

fn extract(path_to_rts: &Utf8Path) -> Result<TempDir> {
ensure!(
path_to_rts.try_exists().unwrap_or(false),
"{path_to_rts} doesn't exist"
);
ensure!(path_to_rts.is_file(), "{path_to_rts} should be a file!");
let temp_dir = TempDir::new_in(path_to_rts.parent().unwrap())
.wrap_err("failed to create temporary extract dir")?;
let extract_dir = temp_dir.path();
let result = run_cmd! {
cd $extract_dir;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these bash snippets scare me.

Copy link
Collaborator Author

@TheButlah TheButlah May 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

its not actually bash. This is just a macro that calls std::process:Command. You can read more here: https://docs.rs/cmd_lib/latest/cmd_lib/#why-you-need-this.

I chose to use cli tools to keep it simpler, but nothing prevents us from replacing those runtime dependencies later.

Note that all dependencies are frozen anyway due to the nix config on the HIL.

info extracting rts $path_to_rts;
tar xvf $path_to_rts;
info finished extract!;
};
result
.wrap_err("failed to extract rts")
.with_note(|| format!("path_to_rts was {path_to_rts}"))?;
Ok(temp_dir)
}

fn flash_cmd(variant: FlashVariant, extracted_dir: &Path) -> Result<()> {
let bootloader_dir = extracted_dir.join("ready-to-sign").join("bootloader");
ensure!(
bootloader_dir.try_exists().unwrap_or(false),
"{bootloader_dir:?} doesn't exist"
);

let cmd_file_name = variant.file_name();
let result = run_cmd! {
cd $bootloader_dir;
info running $cmd_file_name;
bash $cmd_file_name;
info finished flashing!;
};
result
.wrap_err("failed to flash rts")
.with_note(|| format!("bootloader_dir was {bootloader_dir:?}"))?;
Ok(())
}
Loading
Loading