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

add oyster cvm doctor and build #19

Merged
merged 14 commits into from
Dec 24, 2024
21 changes: 21 additions & 0 deletions cli/oyster-cvm/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Generated by Cargo
# will have compiled files and executables
debug/
target/

# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
Cargo.lock
vg-27 marked this conversation as resolved.
Show resolved Hide resolved

# These are backup files generated by rustfmt
**/*.rs.bk

# MSVC Windows builds of rustc generate these, which store debugging information
*.pdb

# RustRover
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
10 changes: 10 additions & 0 deletions cli/oyster-cvm/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[package]
name = "oyster-cvm"
version = "0.1.0"
edition = "2021"

[dependencies]
clap = { version = "4.2.7", features = ["derive"] }
anyhow = "1.0.72"
log = "0.4"
env_logger = "0.10"
Copy link
Member

Choose a reason for hiding this comment

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

remove?

45 changes: 45 additions & 0 deletions cli/oyster-cvm/src/commands/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
use crate::types::Platform;
use anyhow::{Context, Result};
use log::info;
use std::process::Command;

pub fn build_enclave_image(
platform: Platform,
docker_compose: &str,
docker_images: &[String],
output: &str,
) -> Result<()> {
info!("Building enclave image with:");
info!(" Platform: {}", platform.as_str());
info!(" Docker compose: {}", docker_compose);
info!(" Docker images: {}", docker_images.join(", "));

let docker_images_list = docker_images.join(" ");

let nix_expr = format!(
r#"((builtins.getFlake "github:marlinprotocol/oyster-monorepo").packages.{}.sdks.docker-enclave.override {{compose={};dockerImages=[{}];}}).default"#,
platform.nix_arch(),
docker_compose,
docker_images_list
);

let status = Command::new("nix")
vg-27 marked this conversation as resolved.
Show resolved Hide resolved
.args([
"build",
"--impure",
vg-27 marked this conversation as resolved.
Show resolved Hide resolved
"--expr",
&nix_expr,
"-vL",
"--out-link",
output,
])
.status()
.context("Failed to execute Nix build command")?;

if status.success() {
info!("Build successful: {}", output);
Ok(())
} else {
Err(anyhow::anyhow!("Build failed"))
}
}
28 changes: 28 additions & 0 deletions cli/oyster-cvm/src/commands/doctor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
use crate::types::Dependency;
use anyhow::Result;
use log::{error, info};
use std::process::Command;

pub fn run_doctor() -> Result<()> {
check_dependency(Dependency::Docker)?;
check_dependency(Dependency::Nix)?;
vg-27 marked this conversation as resolved.
Show resolved Hide resolved
Ok(())
}

fn check_dependency(dep: Dependency) -> Result<()> {
if Command::new(dep.command())
.arg("--version")
.output()
.is_err()
{
error!(
"{} is not installed. Please install it from {} and try again",
dep.name(),
dep.install_url()
);
return Err(anyhow::anyhow!("{} is required but not found", dep.name()));
} else {
info!("{} is installed ✓", dep.name());
}
Ok(())
}
2 changes: 2 additions & 0 deletions cli/oyster-cvm/src/commands/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod build;
pub mod doctor;
64 changes: 64 additions & 0 deletions cli/oyster-cvm/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
use anyhow::Result;
use clap::{Parser, Subcommand};
mod commands;
mod types;

fn setup_logging() {
env_logger::builder()
.filter_level(log::LevelFilter::Info)
.format_timestamp(None)
.format_target(false)
.init();
}

#[derive(Parser)]
#[command(about = "AWS Nitro Enclave Image Builder")]
Copy link
Member

Choose a reason for hiding this comment

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

make it "Oyster CVM command line utility" or smth

struct Cli {
#[command(subcommand)]
command: Commands,
}

#[derive(Subcommand)]
enum Commands {
/// Check environment dependencies including Docker & Nix
Doctor,
/// Build Enclave Image
BuildImage {
/// Platform (amd64 or arm64)
#[arg(short, long, value_parser = [types::Platform::AMD64.as_str(), types::Platform::ARM64.as_str()])]
platform: String,

/// Path to docker-compose.yml file
#[arg(short = 'c', long)]
docker_compose: String,

/// List of Docker image .tar file paths
#[arg(short = 'i', long, required = true)]
docker_images: Vec<String>,

/// Output folder name
#[arg(short, long, default_value = "result")]
output: String,
},
}

fn main() -> Result<()> {
setup_logging();

let cli = Cli::parse();

match &cli.command {
Commands::Doctor => commands::doctor::run_doctor()?,
Commands::BuildImage {
platform,
docker_compose,
docker_images,
output,
} => {
let platform = types::Platform::from_str(platform).map_err(|e| anyhow::anyhow!(e))?;
commands::build::build_enclave_image(platform, docker_compose, docker_images, output)?
}
}

Ok(())
}
61 changes: 61 additions & 0 deletions cli/oyster-cvm/src/types.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#[derive(Debug, Clone)]
pub enum Platform {
AMD64,
ARM64,
}

impl Platform {
pub fn as_str(&self) -> &'static str {
match self {
Platform::AMD64 => "amd64",
Platform::ARM64 => "arm64",
}
}

pub fn nix_arch(&self) -> &'static str {
match self {
Platform::AMD64 => "x86_64-linux.musl",
Platform::ARM64 => "aarch64-linux.musl",
}
}

pub fn from_str(s: &str) -> Result<Self, String> {
match s.to_lowercase().as_str() {
"amd64" => Ok(Platform::AMD64),
"arm64" => Ok(Platform::ARM64),
_ => Err(format!(
"Unsupported platform: {}. Only amd64 and arm64 are supported",
s
)),
}
}
}

#[derive(Debug)]
pub enum Dependency {
Docker,
Nix,
}

impl Dependency {
pub fn command(&self) -> &'static str {
match self {
Dependency::Docker => "docker",
Dependency::Nix => "nix",
}
}

pub fn name(&self) -> &'static str {
match self {
Dependency::Docker => "Docker",
Dependency::Nix => "Nix",
}
}

pub fn install_url(&self) -> &'static str {
match self {
Dependency::Docker => "https://docs.docker.com/engine/install/",
Dependency::Nix => "https://github.com/DeterminateSystems/nix-installer",
}
}
}