mirror of
https://github.com/fluencelabs/marine.git
synced 2024-12-12 14:55:32 +00:00
Pass envs to AppService, name modules without .wasm extension (#16)
This commit is contained in:
parent
181c161ffc
commit
77cd79e124
@ -22,7 +22,6 @@ use fluence_faas::FluenceFaaS;
|
|||||||
use fluence_faas::ModulesConfig;
|
use fluence_faas::ModulesConfig;
|
||||||
|
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
const SERVICE_ID_ENV_NAME: &str = "service_id";
|
const SERVICE_ID_ENV_NAME: &str = "service_id";
|
||||||
const SERVICE_LOCAL_DIR_NAME: &str = "local";
|
const SERVICE_LOCAL_DIR_NAME: &str = "local";
|
||||||
@ -37,41 +36,15 @@ pub struct AppService {
|
|||||||
|
|
||||||
impl AppService {
|
impl AppService {
|
||||||
/// Create Service with given modules and service id.
|
/// Create Service with given modules and service id.
|
||||||
pub fn new<I, C, S>(modules: I, config: C, service_id: S) -> Result<Self>
|
pub fn new<C, S>(config: C, service_id: S, envs: Vec<String>) -> Result<Self>
|
||||||
where
|
where
|
||||||
I: IntoIterator<Item = String>,
|
|
||||||
C: TryInto<ModulesConfig>,
|
C: TryInto<ModulesConfig>,
|
||||||
S: AsRef<str>,
|
S: AsRef<str>,
|
||||||
AppServiceError: From<C::Error>,
|
AppServiceError: From<C::Error>,
|
||||||
{
|
{
|
||||||
let config: ModulesConfig = config.try_into()?;
|
let config: ModulesConfig = config.try_into()?;
|
||||||
let service_id = service_id.as_ref();
|
let service_id = service_id.as_ref();
|
||||||
let config = Self::set_env_and_dirs(config, service_id, None)?;
|
let config = Self::set_env_and_dirs(config, service_id, envs)?;
|
||||||
|
|
||||||
let modules = modules.into_iter().collect();
|
|
||||||
let faas = FluenceFaaS::with_module_names(&modules, config)?;
|
|
||||||
|
|
||||||
Ok(Self { faas })
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create Service with given raw config, service id and service base dir.
|
|
||||||
pub fn with_raw_config<P, SI>(
|
|
||||||
config: P,
|
|
||||||
service_id: SI,
|
|
||||||
service_base_dir: Option<&str>,
|
|
||||||
) -> Result<Self>
|
|
||||||
where
|
|
||||||
P: Into<PathBuf>,
|
|
||||||
SI: AsRef<str>,
|
|
||||||
{
|
|
||||||
let service_id = service_id.as_ref();
|
|
||||||
let service_base_dir = service_base_dir;
|
|
||||||
|
|
||||||
let config_content = std::fs::read(config.into())?;
|
|
||||||
let config: crate::RawModulesConfig = toml::from_slice(&config_content)?;
|
|
||||||
|
|
||||||
let config = config.try_into()?;
|
|
||||||
let config = Self::set_env_and_dirs(config, service_id, service_base_dir)?;
|
|
||||||
|
|
||||||
let faas = FluenceFaaS::with_raw_config(config)?;
|
let faas = FluenceFaaS::with_raw_config(config)?;
|
||||||
|
|
||||||
@ -106,11 +79,10 @@ impl AppService {
|
|||||||
fn set_env_and_dirs(
|
fn set_env_and_dirs(
|
||||||
mut config: ModulesConfig,
|
mut config: ModulesConfig,
|
||||||
service_id: &str,
|
service_id: &str,
|
||||||
service_base_dir: Option<&str>,
|
mut envs: Vec<String>,
|
||||||
) -> Result<ModulesConfig> {
|
) -> Result<ModulesConfig> {
|
||||||
let base_dir = match (&config.service_base_dir, service_base_dir) {
|
let base_dir = match config.service_base_dir.as_ref() {
|
||||||
(_, Some(base_dir)) => base_dir,
|
Some(base_dir) => base_dir,
|
||||||
(Some(ref base_dir), None) => base_dir,
|
|
||||||
_ => {
|
_ => {
|
||||||
return Err(AppServiceError::IOError(String::from(
|
return Err(AppServiceError::IOError(String::from(
|
||||||
"service_base_dir should be specified",
|
"service_base_dir should be specified",
|
||||||
@ -130,19 +102,19 @@ impl AppService {
|
|||||||
let local_dir: String = local_dir_path.to_string_lossy().into();
|
let local_dir: String = local_dir_path.to_string_lossy().into();
|
||||||
let tmp_dir: String = tmp_dir_path.to_string_lossy().into();
|
let tmp_dir: String = tmp_dir_path.to_string_lossy().into();
|
||||||
|
|
||||||
let service_id_env = vec![format!("{}={}", SERVICE_ID_ENV_NAME, service_id).into_bytes()];
|
|
||||||
let preopened_files = vec![local_dir.clone(), tmp_dir.clone()];
|
let preopened_files = vec![local_dir.clone(), tmp_dir.clone()];
|
||||||
let mapped_dirs = vec![
|
let mapped_dirs = vec![
|
||||||
(String::from(SERVICE_LOCAL_DIR_NAME), local_dir),
|
(String::from(SERVICE_LOCAL_DIR_NAME), local_dir),
|
||||||
(String::from(SERVICE_TMP_DIR_NAME), tmp_dir),
|
(String::from(SERVICE_TMP_DIR_NAME), tmp_dir),
|
||||||
];
|
];
|
||||||
|
envs.push(format!("{}={}", SERVICE_ID_ENV_NAME, service_id));
|
||||||
|
|
||||||
config.modules_config = config
|
config.modules_config = config
|
||||||
.modules_config
|
.modules_config
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(name, module_config)| {
|
.map(|(name, module_config)| {
|
||||||
let module_config = module_config
|
let module_config = module_config
|
||||||
.extend_wasi_envs(service_id_env.clone())
|
.extend_wasi_envs(envs.iter().map(|s| s.clone().into_bytes()).collect())
|
||||||
.extend_wasi_files(preopened_files.clone(), mapped_dirs.clone());
|
.extend_wasi_files(preopened_files.clone(), mapped_dirs.clone());
|
||||||
|
|
||||||
(name, module_config)
|
(name, module_config)
|
||||||
|
@ -27,24 +27,30 @@ use std::convert::TryInto;
|
|||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::PathBuf;
|
use std::path::{PathBuf, Path};
|
||||||
|
|
||||||
// TODO: remove and use mutex instead
|
// TODO: remove and use mutex instead
|
||||||
unsafe impl Send for FluenceFaaS {}
|
unsafe impl Send for FluenceFaaS {}
|
||||||
|
|
||||||
/// Strategy for module loading: either `All`, or only those specified in `Named`
|
/// Strategies for module loading.
|
||||||
pub enum ModulesLoadStrategy<'a> {
|
pub enum ModulesLoadStrategy<'a> {
|
||||||
|
/// Try to load all files in a given directory
|
||||||
|
#[allow(dead_code)]
|
||||||
All,
|
All,
|
||||||
|
/// Try to load only files contained in the set
|
||||||
Named(&'a HashSet<String>),
|
Named(&'a HashSet<String>),
|
||||||
|
/// In a given directory, try to load all files ending with .wasm
|
||||||
|
WasmOnly,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ModulesLoadStrategy<'a> {
|
impl<'a> ModulesLoadStrategy<'a> {
|
||||||
#[inline]
|
#[inline]
|
||||||
/// Returns true if `module` should be loaded.
|
/// Returns true if `module` should be loaded.
|
||||||
pub fn should_load(&self, module: &str) -> bool {
|
pub fn should_load(&self, module: &Path) -> bool {
|
||||||
match self {
|
match self {
|
||||||
ModulesLoadStrategy::All => true,
|
ModulesLoadStrategy::All => true,
|
||||||
ModulesLoadStrategy::Named(set) => set.contains(module),
|
ModulesLoadStrategy::Named(set) => set.contains(module.to_string_lossy().as_ref()),
|
||||||
|
ModulesLoadStrategy::WasmOnly => module.extension().map_or(false, |e| e == ".wasm"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,6 +76,19 @@ impl<'a> ModulesLoadStrategy<'a> {
|
|||||||
_ => <_>::default(),
|
_ => <_>::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn extract_module_name(&self, module: String) -> String {
|
||||||
|
match self {
|
||||||
|
ModulesLoadStrategy::WasmOnly => {
|
||||||
|
let path: &Path = module.as_ref();
|
||||||
|
path.file_stem()
|
||||||
|
.map(|s| s.to_string_lossy().to_string())
|
||||||
|
.unwrap_or(module)
|
||||||
|
}
|
||||||
|
_ => module,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct FluenceFaaS {
|
pub struct FluenceFaaS {
|
||||||
@ -94,7 +113,7 @@ impl FluenceFaaS {
|
|||||||
.modules_dir
|
.modules_dir
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map_or(Ok(HashMap::new()), |dir| {
|
.map_or(Ok(HashMap::new()), |dir| {
|
||||||
Self::load_modules(dir, ModulesLoadStrategy::All)
|
Self::load_modules(dir, ModulesLoadStrategy::WasmOnly)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
Self::with_modules::<ModulesConfig>(modules, config)
|
Self::with_modules::<ModulesConfig>(modules, config)
|
||||||
@ -171,11 +190,12 @@ impl FluenceFaaS {
|
|||||||
.into_string()
|
.into_string()
|
||||||
.map_err(|name| IOError(format!("invalid file name: {:?}", name)))?;
|
.map_err(|name| IOError(format!("invalid file name: {:?}", name)))?;
|
||||||
|
|
||||||
if modules.should_load(&module_name) {
|
if modules.should_load(&module_name.as_ref()) {
|
||||||
let module_bytes = fs::read(path)?;
|
let module_bytes = fs::read(path)?;
|
||||||
|
let module_name = modules.extract_module_name(module_name);
|
||||||
if hash_map.insert(module_name, module_bytes).is_some() {
|
if hash_map.insert(module_name, module_bytes).is_some() {
|
||||||
return Err(FaaSError::ConfigParseError(String::from(
|
return Err(FaaSError::ConfigParseError(String::from(
|
||||||
"config contains modules with the same name",
|
"module {} is duplicated in config",
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ use serde_derive::Serialize;
|
|||||||
use serde_derive::Deserialize;
|
use serde_derive::Deserialize;
|
||||||
|
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
An example of the config:
|
An example of the config:
|
||||||
@ -60,10 +61,22 @@ service_base_dir = "/Users/user/tmp"
|
|||||||
pub struct RawModulesConfig {
|
pub struct RawModulesConfig {
|
||||||
pub modules_dir: Option<String>,
|
pub modules_dir: Option<String>,
|
||||||
pub service_base_dir: Option<String>,
|
pub service_base_dir: Option<String>,
|
||||||
|
#[serde(skip_serializing_if = "Vec::is_empty")]
|
||||||
pub module: Vec<RawModuleConfig>,
|
pub module: Vec<RawModuleConfig>,
|
||||||
pub default: Option<RawDefaultModuleConfig>,
|
pub default: Option<RawDefaultModuleConfig>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl RawModulesConfig {
|
||||||
|
/// Load config from filesystem
|
||||||
|
pub fn load<P: Into<PathBuf>>(path: P) -> Result<Self> {
|
||||||
|
let path = path.into();
|
||||||
|
let bytes = std::fs::read(&path)?;
|
||||||
|
toml::from_slice(bytes.as_slice()).map_err(|e| {
|
||||||
|
FaaSError::ConfigParseError(format!("Error parsing config {:?}: {:?}", path, e))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl TryInto<ModulesConfig> for RawModulesConfig {
|
impl TryInto<ModulesConfig> for RawModulesConfig {
|
||||||
type Error = FaaSError;
|
type Error = FaaSError;
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
use crate::Result;
|
use crate::Result;
|
||||||
|
|
||||||
use fluence_app_service::AppService;
|
use fluence_app_service::{AppService, RawModulesConfig};
|
||||||
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
@ -162,18 +162,15 @@ impl REPL {
|
|||||||
let service_id = uuid::Uuid::new_v4().to_string();
|
let service_id = uuid::Uuid::new_v4().to_string();
|
||||||
|
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
let app_service = match config_file_path {
|
|
||||||
Some(config_file_path) => {
|
|
||||||
let config_file_path = config_file_path.into();
|
|
||||||
AppService::with_raw_config(config_file_path, &service_id, Some(&tmp_path))
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
let mut config: fluence_app_service::RawModulesConfig = <_>::default();
|
|
||||||
config.service_base_dir = Some(tmp_path);
|
|
||||||
|
|
||||||
AppService::new(std::iter::empty(), config, &service_id)
|
let mut config = config_file_path
|
||||||
}
|
.map(|p| RawModulesConfig::load(p.into()))
|
||||||
}?;
|
.transpose()?
|
||||||
|
.unwrap_or_default();
|
||||||
|
config.service_base_dir = Some(tmp_path);
|
||||||
|
|
||||||
|
let app_service = AppService::new(config, &service_id, vec![])?;
|
||||||
|
|
||||||
let duration = start.elapsed();
|
let duration = start.elapsed();
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
|
Loading…
Reference in New Issue
Block a user