ya_runtime_wasi/
entrypoint.rs1use crate::{deploy::DeployFile, manifest::WasmImage, wasmtime_unit::Wasmtime};
2
3use std::path::{Component, Path, PathBuf};
4
5use anyhow::{bail, Result};
6use log::info;
7
8pub fn start(workdir: impl AsRef<Path>) -> Result<()> {
12 let workdir = workdir.as_ref();
13 let deploy_file = DeployFile::load(workdir)?;
14
15 info!(
16 "Validating deployed image {:?}.",
17 get_log_path(workdir, deploy_file.image_path())
18 );
19
20 let mut image = WasmImage::new(&deploy_file.image_path())?;
21 let mut wasmtime = create_wasmtime(workdir, &mut image, &deploy_file)?;
22
23 wasmtime.load_binaries(&mut image)?;
24
25 info!("Validation completed.");
26
27 Ok(())
28}
29
30pub fn run(
50 workdir: impl AsRef<Path>,
51 entrypoint: impl AsRef<str>,
52 args: impl IntoIterator<Item = String>,
53) -> Result<()> {
54 let workdir = workdir.as_ref();
55 let deploy_file = DeployFile::load(workdir)?;
56
57 let mut image = WasmImage::new(&deploy_file.image_path())?;
58 let mut wasmtime = create_wasmtime(workdir, &mut image, &deploy_file)?;
59
60 info!(
61 "Running image: {:?}",
62 get_log_path(workdir, deploy_file.image_path())
63 );
64 info!("Running image: {}", deploy_file.image_path().display());
65
66 let entrypoint = image.find_entrypoint(entrypoint.as_ref())?;
69 wasmtime.load_binary(&mut image, &entrypoint)?;
70 wasmtime.run(entrypoint, args.into_iter().collect())?;
71
72 info!("Computations completed.");
73
74 Ok(())
75}
76
77pub(crate) struct DirectoryMount {
78 pub host: PathBuf,
79 pub guest: PathBuf,
80}
81
82fn create_wasmtime(
83 workdir: &Path,
84 _image: &mut WasmImage,
85 deploy: &DeployFile,
86) -> Result<Wasmtime> {
87 let mounts = deploy
88 .vols()
89 .map(|v| {
90 let host = workdir.join(&v.name);
91 let guest = PathBuf::from(&v.path);
92 validate_mount_path(&guest)?;
93 Ok(DirectoryMount { host, guest })
94 })
95 .collect::<anyhow::Result<Vec<_>>>()?;
96 Ok(Wasmtime::new(mounts))
97}
98
99fn validate_mount_path(path: &Path) -> Result<()> {
100 let path = PathBuf::from(path);
103 for component in path.components() {
104 match component {
105 Component::Prefix { .. } => {
106 bail!("Expected unix path instead of [{}].", path.display())
107 }
108 Component::ParentDir { .. } => {
109 bail!("Path [{}] contains illegal '..' component.", path.display())
110 }
111 Component::CurDir => bail!("Path [{}] contains illegal '.' component.", path.display()),
112 _ => (),
113 }
114 }
115 Ok(())
116}
117
118fn get_log_path<'a>(workdir: &'a Path, path: &'a Path) -> &'a Path {
119 path.strip_prefix(workdir)
121 .ok()
122 .or_else(|| path.file_name().map(|file_name| Path::new(file_name)))
124 .unwrap_or_else(|| Path::new(""))
126}
127
128#[cfg(test)]
129mod tests {
130 use super::*;
131
132 #[test]
133 fn test_mount_path_validation() {
134 assert_eq!(
135 validate_mount_path(&PathBuf::from("path/path/path")).is_err(),
136 false
137 );
138 assert_eq!(
139 validate_mount_path(&PathBuf::from("path/../path")).is_err(),
140 true
141 );
142 assert_eq!(
143 validate_mount_path(&PathBuf::from("./path/../path")).is_err(),
144 true
145 );
146 assert_eq!(
147 validate_mount_path(&PathBuf::from("./path/path")).is_err(),
148 true
149 );
150 }
151}