Skip to content
This repository has been archived by the owner on Feb 3, 2023. It is now read-only.

Commit

Permalink
Merge pull request #840 from holochain/container-admin-functions
Browse files Browse the repository at this point in the history
Container Admin Functions (DNA/instance management)
  • Loading branch information
Nicolas Luck authored Jan 17, 2019
2 parents 041ac7c + 5e64766 commit 8a6644f
Show file tree
Hide file tree
Showing 17 changed files with 1,145 additions and 94 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,5 @@ cobertura.xml
container/example-config/tmp-storage/*
container/tmp-storage/*
container_api/tmp-storage/*
tmp-test-container-config.toml
tmp-*-container-config.toml
10 changes: 8 additions & 2 deletions cmd/src/cli/run.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
use cli::{self, package};
use colored::*;
use error::DefaultResult;
use holochain_container_api::{config::*, container::Container, logger::LogRules};
use holochain_container_api::{
config::*,
container::{mount_container_from_config, CONTAINER},
logger::LogRules,
};
use holochain_core_types::agent::AgentId;
use std::{env, fs};

Expand Down Expand Up @@ -118,7 +122,9 @@ pub fn run(
..Default::default()
};

let mut container = Container::from_config(base_config.clone());
mount_container_from_config(base_config);
let mut container_guard = CONTAINER.lock().unwrap();
let container = container_guard.as_mut().expect("Container must be mounted");

container
.load_config()
Expand Down
5 changes: 4 additions & 1 deletion container/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,12 @@ bootstrap_nodes = []

TBD (for now you just have infer from the example!)

## Limitations
## Testing HTTP interface using cURL

Currently the container supports the `websocket` and `http` interfaces.
Assuming the container http interface is running on port 4000 it can be tested by running:
`curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":"0","method":"info/instances"}' http://localhost:4000`


## Contribute
Holochain is an open source project. We welcome all sorts of participation and are actively working on increasing surface area to accept it. Please see our [contributing guidelines](../CONTRIBUTING.md) for our general practices and protocols on participating in the community.
Expand Down
56 changes: 45 additions & 11 deletions container/example-config/basic.toml
Original file line number Diff line number Diff line change
@@ -1,46 +1,80 @@
bridges = []

[[agents]]
id = "test agent 1"
key_file = "holo_tester.key"
name = "Holo Tester 1"
public_address = "HoloTester1-----------------------------------------------------------------------AAACZp4xHB"
key_file = "holo_tester.key"

[[agents]]
id = "test agent 2"
key_file = "holo_tester.key"
name = "Holo Tester 2"
public_address = "HoloTester2-----------------------------------------------------------------------AAAGy4WW9e"
key_file = "holo_tester.key"

[[dnas]]
id = "app spec rust"
file = "example-config/app_spec.hcpkg"
hash = "Qm328wyq38924y"
id = "app spec rust"

[[instances]]
id = "app spec instance 1"
dna = "app spec rust"
agent = "test agent 1"
dna = "app spec rust"
id = "app spec instance 1"

[instances.storage]
type = "file"
path = "example-config/tmp-storage"
type = "file"

[[instances]]
id = "app spec instance 2"
dna = "app spec rust"
agent = "test agent 2"
dna = "app spec rust"
id = "app spec instance 2"

[instances.storage]
type = "file"
path = "example-config/tmp-storage"

type = "file"

[[interfaces]]
admin = true
id = "websocket interface"

[[interfaces.instances]]
id = "app spec instance 1"

[[interfaces.instances]]
id = "app spec instance 2"

[interfaces.driver]
type = "websocket"
port = 3000
type = "websocket"

[[interfaces]]
admin = true
id = "http interface"

[[interfaces.instances]]
id = "app spec instance 1"

[[interfaces.instances]]
id = "app spec instance 2"

[interfaces.driver]
port = 4000
type = "http"

[logger]
type = "debug"
[[logger.rules.rules]]
color = "red"
exclude = false
pattern = "^err/"

[[logger.rules.rules]]
color = "white"
exclude = false
pattern = "^debug/dna"

[[logger.rules.rules]]
exclude = false
pattern = ".*"
28 changes: 28 additions & 0 deletions container/example-config/empty-container.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
[[agents]]
id = "test agent 1"
name = "Holo Tester 1"
public_address = "HoloTester1-----------------------------------------------------------------------AAACZp4xHB"
key_file = "holo_tester.key"

dnas = []

instances = []

[[interfaces]]
admin = true
id = "http interface"
instances = []
[interfaces.driver]
type = "http"
port = 4000

[[interfaces]]
admin = true
id = "websocket interface"
instances = []
[interfaces.driver]
type = "websocket"
port = 3000

[logger]
type = "debug"
21 changes: 12 additions & 9 deletions container/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ extern crate structopt;

use holochain_container_api::{
config::{load_configuration, Configuration},
container::Container,
container::{mount_container_from_config, CONTAINER},
};
use holochain_core_types::error::HolochainError;
use std::{fs::File, io::prelude::*, path::PathBuf};
Expand All @@ -44,8 +44,10 @@ fn main() {
let config_path_str = config_path.to_str().unwrap();
println!("Using config path: {}", config_path_str);
match bootstrap_from_config(config_path_str) {
Ok(mut container) => {
if container.instances().len() > 0 {
Ok(()) => {
{
let mut container_guard = CONTAINER.lock().unwrap();
let mut container = container_guard.as_mut().expect("Container must be mounted");
println!(
"Successfully loaded {} instance configurations",
container.instances().len()
Expand All @@ -57,24 +59,25 @@ fn main() {
println!("Starting interfaces...");
container.start_all_interfaces();
println!("Done.");
loop {}
} else {
println!("No instance started, bailing...");
}
loop {}
}
Err(error) => println!("Error while trying to boot from config: {:?}", error),
};
}

#[cfg_attr(tarpaulin, skip)]
fn bootstrap_from_config(path: &str) -> Result<Container, HolochainError> {
fn bootstrap_from_config(path: &str) -> Result<(), HolochainError> {
let config = load_config_file(&String::from(path))?;
config
.check_consistency()
.map_err(|string| HolochainError::ConfigError(string))?;
let mut container = Container::from_config(config);
mount_container_from_config(config);
let mut container_guard = CONTAINER.lock().unwrap();
let container = container_guard.as_mut().expect("Container must be mounted");
container.set_config_path(PathBuf::from(path));
container.load_config()?;
Ok(container)
Ok(())
}

#[cfg_attr(tarpaulin, skip)]
Expand Down
2 changes: 2 additions & 0 deletions container_api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ serde_regex = "0.3.1"
holochain_net_connection = { path = "../net_connection" }
holochain_net_ipc = { path = "../net_ipc" }
maplit = "1.0.1"
dirs = "1.0.4"
lazy_static = "1.2.0"
directories = "1.0"

[dev-dependencies]
Expand Down
45 changes: 42 additions & 3 deletions container_api/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,10 @@ use toml;
pub struct Configuration {
/// List of Agents, this mainly means identities and their keys. Required.
pub agents: Vec<AgentConfiguration>,
/// List of DNAs, for each a path to the DNA file. Required.
/// List of DNAs, for each a path to the DNA file. Optional.
#[serde(default)]
pub dnas: Vec<DnaConfiguration>,
/// List of instances, includes references to an agent and a DNA. Required.
/// List of instances, includes references to an agent and a DNA. Optional.
#[serde(default)]
pub instances: Vec<InstanceConfiguration>,
/// List of interfaces any UI can use to access zome functions. Optional.
Expand Down Expand Up @@ -217,6 +218,31 @@ impl Configuration {
.cloned()
.collect()
}

/// Removes the instance given by id and all mentions of it in other elements so
/// that the config is guaranteed to be valid afterwards if it was before.
pub fn save_remove_instance(mut self, id: &String) -> Self {
self.instances = self
.instances
.into_iter()
.filter(|instance| instance.id != *id)
.collect();

self.interfaces = self
.interfaces
.into_iter()
.map(|mut interface| {
interface.instances = interface
.instances
.into_iter()
.filter(|instance| instance.id != *id)
.collect();
interface
})
.collect();

self
}
}

/// An agent has a name/ID and is defined by a private key that resides in a file
Expand All @@ -237,7 +263,7 @@ impl From<AgentConfiguration> for AgentId {

/// A DNA is represented by a DNA file.
/// A hash has to be provided for sanity check.
#[derive(Deserialize, Serialize, Clone)]
#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
pub struct DnaConfiguration {
pub id: String,
pub file: String,
Expand Down Expand Up @@ -385,6 +411,19 @@ where
})
}

pub fn serialize_configuration(config: &Configuration) -> HcResult<String> {
// see https://github.com/alexcrichton/toml-rs/issues/142
let config_toml = toml::Value::try_from(config).map_err(|e| {
HolochainError::IoError(format!("Could not serialize toml: {}", e.to_string()))
})?;
toml::to_string(&config_toml).map_err(|e| {
HolochainError::IoError(format!(
"Could not convert toml to string: {}",
e.to_string()
))
})
}

#[cfg(test)]
pub mod tests {
use super::*;
Expand Down
Loading

0 comments on commit 8a6644f

Please sign in to comment.