Skip to content

Commit

Permalink
feat(system-services, tests): composable and overridable system servi…
Browse files Browse the repository at this point in the history
…ces [NET-530, NET-531] (#1770)

* made system services distros plugable
* override system services in tests
  • Loading branch information
kmd-fl authored Sep 14, 2023
1 parent 507713d commit 459ec72
Show file tree
Hide file tree
Showing 15 changed files with 712 additions and 353 deletions.
3 changes: 2 additions & 1 deletion Cargo.lock

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

6 changes: 3 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ test:

server:
WASM_LOG="trace" \
RUST_LOG="debug,\
RUST_LOG="info,\
aquamarine::aqua_runtime=off,\
ipfs_effector=off,\
ipfs_pure=off,\
Expand All @@ -32,10 +32,10 @@ server:
wasmer_wasi=info,\
cranelift_codegen=info,\
wasmer_wasi=info,\
run-console=trace,\
run-console=debug,\
wasmtime_cranelift=off,\
wasmtime_jit=off,\
particle_reap=trace" \
particle_reap=debug" \
cargo run --release -p nox

local-env:
Expand Down
1 change: 1 addition & 0 deletions crates/created-swarm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ script-storage = { workspace = true }
fs-utils = { workspace = true }
air-interpreter-fs = { workspace = true }
toy-vms = { workspace = true }
system-services = { workspace = true }

fluence-keypair = { workspace = true }
log = { workspace = true }
Expand Down
35 changes: 30 additions & 5 deletions crates/created-swarm/src/swarm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@ use futures::stream::iter;
use hyper::{Body, Request, StatusCode};
use nox::{Connectivity, Node};
use particle_protocol::ProtocolConfig;
use server_config::{default_script_storage_timer_resolution, BootstrapConfig, UnresolvedConfig};
use server_config::{
default_script_storage_timer_resolution, system_services_config, BootstrapConfig,
UnresolvedConfig,
};
use test_constants::{EXECUTION_TIMEOUT, KEEP_ALIVE_TIMEOUT, TRANSPORT_TIMEOUT};
use tokio::sync::oneshot;
use toy_vms::EasyVM;
Expand Down Expand Up @@ -243,7 +246,8 @@ pub struct SwarmConfig {
pub spell_base_dir: Option<PathBuf>,
pub timer_resolution: Duration,
pub allowed_binaries: Vec<String>,
pub enabled_system_services: Vec<server_config::system_services_config::ServiceKey>,
pub enabled_system_services: Vec<String>,
pub extend_system_services: Vec<system_services::PackageDistro>,
pub http_port: u16,
}

Expand All @@ -266,6 +270,7 @@ impl SwarmConfig {
timer_resolution: default_script_storage_timer_resolution(),
allowed_binaries: vec!["/usr/bin/ipfs".to_string(), "/usr/bin/curl".to_string()],
enabled_system_services: vec![],
extend_system_services: vec![],
http_port: 0,
}
}
Expand Down Expand Up @@ -360,7 +365,14 @@ pub fn create_swarm_with_runtime<RT: AquaRuntime>(

resolved.node_config.script_storage_timer_resolution = config.timer_resolution;
resolved.node_config.allowed_binaries = config.allowed_binaries.clone();
resolved.system_services.enable = config.enabled_system_services.clone();
resolved.system_services.enable = config
.enabled_system_services
.iter()
.map(|service| {
system_services_config::ServiceKey::from_string(service)
.expect(&format!("service {service} doesn't exist"))
})
.collect();

let management_kp = fluence_keypair::KeyPair::generate_ed25519();
let management_peer_id = libp2p::identity::Keypair::from(management_kp.clone())
Expand All @@ -374,8 +386,21 @@ pub fn create_swarm_with_runtime<RT: AquaRuntime>(
listen_on: config.listen_on.clone(),
manager: management_peer_id,
});
let mut node =
Node::new(resolved, vm_config, "some version", "some version").expect("create node");

let system_services_config = resolved.system_services.clone();
let system_service_distros =
system_services::SystemServiceDistros::default_from(system_services_config)
.expect("Failed to get default system service distros")
.extend(config.extend_system_services.clone());

let mut node = Node::new(
resolved,
vm_config,
"some version",
"some version",
system_service_distros,
)
.expect("create node");
node.listen(vec![config.listen_on.clone()]).expect("listen");

(
Expand Down
2 changes: 1 addition & 1 deletion crates/nox-tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ now-millis = { path = "../now-millis" }
local-vm = { path = "../local-vm" }
control-macro = { path = "../control-macro" }
json-utils = { path = "../json-utils" }
server-config = { workspace = true }
system-services = { workspace = true }

log-utils = { workspace = true }
fluence-spell-dtos = { workspace = true }
Expand Down
7 changes: 3 additions & 4 deletions crates/nox-tests/tests/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ use now_millis::now_ms;
use particle_protocol::Particle;
use serde::Deserialize;
use serde_json::{json, Value as JValue};
use server_config::system_services_config::ServiceKey::Registry;
use service_modules::load_module;
use std::collections::HashMap;
use std::str::FromStr;
Expand Down Expand Up @@ -1624,7 +1623,7 @@ async fn sign_verify() {
#[tokio::test]
async fn sign_invalid_tetraplets() {
let swarms = make_swarms_with_cfg(2, |mut cfg| {
cfg.enabled_system_services = vec![Registry];
cfg.enabled_system_services = vec!["registry".to_string()];
cfg
})
.await;
Expand Down Expand Up @@ -1693,7 +1692,7 @@ async fn sign_invalid_tetraplets() {
#[tokio::test]
async fn sig_verify_invalid_signature() {
let swarms = make_swarms_with_cfg(1, |mut cfg| {
cfg.enabled_system_services = vec![Registry];
cfg.enabled_system_services = vec!["registry".to_string()];
cfg
})
.await;
Expand Down Expand Up @@ -1884,7 +1883,7 @@ async fn json_builtins() {
async fn insecure_sign_verify() {
let kp = KeyPair::from_secret_key(INSECURE_KEYPAIR_SEED.collect(), KeyFormat::Ed25519).unwrap();
let swarms = make_swarms_with_cfg(1, |mut cfg| {
cfg.enabled_system_services = vec![Registry];
cfg.enabled_system_services = vec!["registry".to_string()];
cfg
})
.await;
Expand Down
108 changes: 107 additions & 1 deletion crates/nox-tests/tests/services.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![feature(assert_matches)]
/*
* Copyright 2021 Fluence Labs Limited
*
Expand All @@ -16,13 +17,118 @@

use eyre::WrapErr;
use maplit::hashmap;
use serde_json::json;
use serde_json::Value as JValue;
use serde_json::{json, Value};
use std::assert_matches::assert_matches;

use base64::{engine::general_purpose::STANDARD as base64, Engine};
use connected_client::ConnectedClient;
use created_swarm::{make_swarms, make_swarms_with_cfg};
use service_modules::load_module;
use system_services::{PackageDistro, ServiceDistro};

#[tokio::test]
async fn test_system_service_override() {
// We need to include bytes, not read them, since the ServiceDistro expects module bytes as `&'static [u8]`
// It's unnecessary to allow not static links or even vectors since real life we need only this
let module = include_bytes!("./tetraplets/artifacts/tetraplets.wasm");
let config = json!({
"module": [
{
"name": "tetraplets",
"config" : {
"preopened_files": [
[
"tmp"
]
],
}}
]
});

let config = serde_json::from_value(config).expect("parse module config");
let m: &'static [u8] = module;
let service_name = "test-service".to_string();

let service = ServiceDistro {
name: service_name.clone(),
modules: hashmap! {
"tetraplets" => m,
},
config,
};
let name = service_name.clone();
let init: system_services::InitService = Box::new(move |call, status| {
let name = name.clone();
let service_status = status
.services
.get(&name)
.expect("deployment status for the service");
assert_matches!(
service_status,
system_services::ServiceStatus::Created(_),
"wrong deployment status"
);
let result: eyre::Result<_> = call(name.clone(), "not".to_string(), vec![json!(false)]);
assert!(
result.is_err(),
"must be error due to the the call interface restrictions"
);
let error = result.unwrap_err().to_string();
assert_eq!(
error,
format!("Call {}.not return invalid result: true", name),
"the service call must return invalid result due to the call interface restrictions"
);
Ok(())
});
let package = PackageDistro {
name: service_name.clone(),
version: "some-version",
services: vec![service],
spells: vec![],
init: Some(std::sync::Arc::new(init)),
};
let swarms = make_swarms_with_cfg(1, move |mut cfg| {
cfg.extend_system_services = vec![package.clone()];
cfg
})
.await;

let mut client = ConnectedClient::connect_to(swarms[0].multiaddr.clone())
.await
.wrap_err("connect client")
.unwrap();
let data = hashmap! {
"relay" => json!(client.node.to_string()),
};
let response = client
.execute_particle(
r#"
(seq
(call relay ("srv" "list") [] list)
(call %init_peer_id% ("return" "") [list])
)
"#,
data,
)
.await
.unwrap();
if let [Value::Array(list)] = response.as_slice() {
assert_eq!(list.len(), 1, "expected only one service to be installed");
if let Value::Object(obj) = &list[0] {
let aliases = obj
.get("aliases")
.expect("srv.list must return a list of aliases for a service")
.as_array()
.expect("list of aliases must be a list");
assert_eq!(aliases.len(), 1, "test-service must have only 1 alias");
assert_eq!(aliases[0], service_name, "wrong alias for the test-service");
}
} else {
panic!("wrong result, expected list of services")
}
}

#[tokio::test]
async fn create_service_from_config() {
Expand Down
3 changes: 1 addition & 2 deletions crates/nox-tests/tests/spells.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1420,8 +1420,7 @@ async fn resolve_global_alias() {
#[tokio::test]
async fn worker_sig_test() {
let swarms = make_swarms_with_cfg(1, |mut cfg| {
cfg.enabled_system_services =
vec![server_config::system_services_config::ServiceKey::Registry];
cfg.enabled_system_services = vec!["registry".to_string()];
cfg
})
.await;
Expand Down
10 changes: 10 additions & 0 deletions crates/server-config/src/system_services_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,16 @@ impl ServiceKey {
Self::Decider,
]
}

pub fn from_string(name: &str) -> Option<ServiceKey> {
match name {
"aqua-ipfs" => Some(ServiceKey::AquaIpfs),
"trust-graph" => Some(ServiceKey::TrustGraph),
"registry" => Some(ServiceKey::Registry),
"decider" => Some(ServiceKey::Decider),
_ => None,
}
}
}

impl std::fmt::Display for ServiceKey {
Expand Down
Loading

0 comments on commit 459ec72

Please sign in to comment.