Skip to content
This repository has been archived by the owner on Nov 10, 2022. It is now read-only.

Add deployment configuration file #1

Merged
merged 2 commits into from
Sep 4, 2020
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
549 changes: 221 additions & 328 deletions Cargo.lock

Large diffs are not rendered by default.

19 changes: 16 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,28 @@ is-it-maintained-issue-resolution = { repository = "enarx/enarx-wasmldr" }
is-it-maintained-open-issues = { repository = "enarx/enarx-wasmldr" }

[dependencies]
wasmtime = { version = "0.19.0", default-features = false }
wasmtime-wasi = { version = "0.19.1", default-features = false }
wasi-common = { version = "0.19.1", default-features = false }
wasmtime = { git = "https://github.com/bytecodealliance/wasmtime.git", rev = "8ac4bd1d0d8228b97a88b1841cfc0247e9ef4306", default-features = false }
wasmtime-wasi = { git = "https://github.com/bytecodealliance/wasmtime.git", rev = "8ac4bd1d0d8228b97a88b1841cfc0247e9ef4306", default-features = false }
wasi-common = { git = "https://github.com/bytecodealliance/wasmtime.git", rev = "8ac4bd1d0d8228b97a88b1841cfc0247e9ef4306", default-features = false }
env_logger = "0.7"
log = "0.4"

wasmparser = "0.62"
leb128 = "0.2"
tar = "0.4"
tempfile = "3"
clap = "2.33"

serde = { version = "1.0", features = ["derive"] }
serde_yaml = "0.8"

[build-dependencies]
wat = "1.0"

[[bin]]
name = "enarx-wasmres"
path = "src/enarx-wasmres.rs"

[profile.release]
incremental = false
codegen-units = 1
Expand Down
17 changes: 10 additions & 7 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,16 @@ fn main() {
for entry in in_dir.read_dir().unwrap() {
if let Ok(entry) = entry {
let wat = entry.path();
if wat.extension().unwrap() == "wat" {
let wasm = out_dir
.join(wat.file_name().unwrap())
.with_extension("wasm");
let binary = wat::parse_file(&wat).expect("Can't parse wat file");
std::fs::write(wasm, &binary).expect("Can't write wasm file");
println!("cargo:rerun-if-changed={}", &wat.display());
match wat.extension() {
Some(ext) if ext == "wat" => {
let wasm = out_dir
.join(wat.file_name().unwrap())
.with_extension("wasm");
let binary = wat::parse_file(&wat).expect("Can't parse wat file");
std::fs::write(wasm, &binary).expect("Can't write wasm file");
println!("cargo:rerun-if-changed={}", &wat.display());
}
_ => {}
}
}
}
Expand Down
8 changes: 8 additions & 0 deletions fixtures/bundle/config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
stdio:
stdin:
Bundle: stdin.txt
stdout:
File: stdout.txt
stderr:
File: stderr.txt
1 change: 1 addition & 0 deletions fixtures/bundle/stdin.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Hello world!
184 changes: 184 additions & 0 deletions src/bundle.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
// SPDX-License-Identifier: Apache-2.0

#![allow(dead_code)]

use std::io::prelude::*;
use std::io::{ErrorKind, Read, Result, Write};
use std::path::{Path, PathBuf};
use wasmparser::{Chunk, Parser, Payload::*};

pub const RESOURCES_SECTION: &str = ".enarx.resources";

pub struct Builder {
paths: Vec<PathBuf>,
prefix: Option<String>,
section: Option<String>,
}

impl Builder {
pub fn new() -> Self {
Self {
paths: Vec::new(),
prefix: None,
section: None,
}
}

pub fn path(&mut self, path: impl AsRef<Path>) -> &mut Self {
self.paths.push(path.as_ref().into());
self
}

pub fn prefix(&mut self, prefix: &str) -> &mut Self {
self.prefix = Some(prefix.to_string());
self
}

pub fn section(&mut self, section: &str) -> &mut Self {
self.section = Some(section.to_string());
self
}

pub fn build(&mut self, input: impl Read, mut output: impl Write) -> Result<()> {
let prefix = match &self.prefix {
Some(prefix) => prefix.as_str(),
None => "",
};
let mut archive = tempfile::tempfile()?;
create_archive(&self.paths, prefix, &mut archive)?;

let section = match &self.section {
Some(section) => section.as_str(),
None => RESOURCES_SECTION,
};
parse(input, section, |_| Ok(()), |bytes| output.write_all(bytes))?;
append_archive(&mut output, section, &archive)?;
Ok(())
}
}

fn create_archive<P: AsRef<Path>>(
paths: impl IntoIterator<Item = P>,
prefix: &str,
writer: &mut impl Write,
) -> Result<()> {
let mut builder = tar::Builder::new(writer);

for path in paths {
for ancestor in path.as_ref().ancestors() {
if ancestor == Path::new("") {
break;
}
let metadata = std::fs::metadata(&ancestor)?;
if !metadata.is_dir() && !metadata.is_file() {
return Err(ErrorKind::InvalidInput.into());
}
}
let name = path
.as_ref()
.strip_prefix(prefix)
.or(Err(ErrorKind::InvalidInput))?;
builder.append_path_with_name(&path, &name)?;
}

builder.finish()?;

Ok(())
}

pub fn parse(
mut input: impl Read,
section: &str,
mut handle_custom: impl FnMut(&[u8]) -> Result<()>,
mut handle_default: impl FnMut(&[u8]) -> Result<()>,
) -> Result<()> {
let mut buf = Vec::new();
let mut parser = Parser::new(0);
let mut eof = false;
let mut stack = Vec::new();

loop {
let (payload, consumed) = match parser.parse(&buf, eof).or(Err(ErrorKind::InvalidInput))? {
Chunk::NeedMoreData(hint) => {
assert!(!eof); // otherwise an error would be returned

// Use the hint to preallocate more space, then read
// some more data into our buffer.
//
// Note that the buffer management here is not ideal,
// but it's compact enough to fit in an example!
let len = buf.len();
buf.extend((0..hint).map(|_| 0u8));
let n = input.read(&mut buf[len..])?;
buf.truncate(len + n);
eof = n == 0;
continue;
}

Chunk::Parsed { consumed, payload } => (payload, consumed),
};

match payload {
CustomSection { name, data, .. } => {
if name == section {
handle_custom(data)?;
} else {
handle_default(&buf[..consumed])?;
}
}
// When parsing nested modules we need to switch which
// `Parser` we're using.
ModuleCodeSectionEntry {
parser: subparser, ..
} => {
stack.push(parser);
parser = subparser;
}
End => {
if let Some(parent_parser) = stack.pop() {
parser = parent_parser;
} else {
break;
}
}
_ => {
handle_default(&buf[..consumed])?;
}
}

// once we're done processing the payload we can forget the
// original.
buf.drain(..consumed);
}
Ok(())
}

fn append_archive(
writer: &mut impl Write,
section: &str,
mut archive: &std::fs::File,
) -> Result<()> {
let mut header: Vec<u8> = Vec::new();
let name = section.as_bytes();
leb128::write::unsigned(&mut header, name.len() as u64)?;
header.write_all(name)?;
let size = archive.seek(std::io::SeekFrom::End(0))?;

writer.write_all(&[0])?;
leb128::write::unsigned(writer, size + header.len() as u64)?;
writer.write_all(&header)?;

let _ = archive.seek(std::io::SeekFrom::Start(0))?;
loop {
let mut buf = [0; 4096];
let n = archive.read(&mut buf[..])?;

if n == 0 {
break;
}

writer.write_all(&buf[..n])?;
}

Ok(())
}
27 changes: 27 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// SPDX-License-Identifier: Apache-2.0
use serde::{Deserialize, Serialize};
use std::path::PathBuf;

#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub enum Handle {
/// Inherit from the parent process
Inherit,

/// External file
File(PathBuf),

/// File bundled in the Wasm binary
Bundle(PathBuf),
}

#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct Stdio {
pub stdin: Option<Handle>,
pub stdout: Option<Handle>,
pub stderr: Option<Handle>,
}

#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct Config {
pub stdio: Stdio,
}
78 changes: 78 additions & 0 deletions src/enarx-wasmres.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// SPDX-License-Identifier: Apache-2.0

mod bundle;

use clap::{App, Arg};
use std::io::{BufRead, BufReader, Read, Result};
use std::path::PathBuf;

fn add_paths(builder: &mut bundle::Builder, reader: &mut impl Read) -> Result<()> {
let mut reader = BufReader::new(reader);

loop {
let mut buf = String::new();
let size = reader.read_line(&mut buf)?;
if size == 0 {
break;
}

let path: PathBuf = buf.trim_end().into();
builder.path(path);
}

Ok(())
}

fn main() {
let matches = App::new("enarx-wasmres")
.about("Bundle resource files into a Wasm file")
.arg(
Arg::with_name("INPUT")
.help("Sets the input Wasm file")
.required(true)
.index(1),
)
.arg(
Arg::with_name("OUTPUT")
.help("Sets the output Wasm file")
.required(true)
.index(2),
)
.arg(
Arg::with_name("prefix")
.help("Sets the path prefix to be removed")
.short("-p")
.long("prefix")
.takes_value(true)
.default_value(""),
)
.arg(
Arg::with_name("section")
.help("Sets the section name")
.short("-j")
.long("section")
.takes_value(true)
.default_value(bundle::RESOURCES_SECTION),
)
.usage("find dir -type f | enarx-wasmres INPUT OUTPUT")
.get_matches();

let input_path = matches.value_of("INPUT").unwrap();
let output_path = matches.value_of("OUTPUT").unwrap();

let mut builder = bundle::Builder::new();
let mut reader = std::io::stdin();
add_paths(&mut builder, &mut reader).expect("couldn't read file list");

let prefix = matches.value_of("prefix").unwrap();
let section = matches.value_of("section").unwrap();

builder.prefix(prefix).section(section);

let input = std::fs::read(&input_path).expect("couldn't open input file");
let mut output = std::fs::File::create(&output_path).expect("couldn't create output file");

builder
.build(input.as_slice(), &mut output)
.expect("couldn't append custom section");
}
3 changes: 3 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
#![deny(missing_docs)]
#![deny(clippy::all)]

mod bundle;
mod config;
mod virtfs;
mod workload;

use log::info;
Expand Down
Loading