-
Notifications
You must be signed in to change notification settings - Fork 267
Container Admin Functions (DNA/instance management) #840
Conversation
…m interface threads
I'm concerned about introducing a singleton for this. Singletons and tests do not mix well. As long as we can keep this singleton completely out of tests, it should be OK. But the moment we want two Containers in one process, we are screwed. I think the way to do this without a singleton would be to build the IoHandler and the Container at the same time. ContainerApiBuilder might become ContainerBuilder. The ContainerBuilder would build the Container and return it as an |
Making this visible, from Lucksus: " |
In response to the above I can call
and
|
…_dna_from_file to response
|
@willemolding, yeah, after the config was changed, the container actually needs to reload the config in a proper way.. I was anticipating that. |
…ain/holochain-rust into container-admin-functions # Conflicts: # container_api/src/container.rs # container_api/src/container_admin.rs # container_api/src/interface.rs
…in container/main.rs
container_api/src/interface.rs
Outdated
/// To be consistent with holochain function calls the expected output of the admin calls | ||
/// is stringified JSON. This performs that stringification and then wraps it in the format expected | ||
/// by the jsonrpc add_method closure | ||
fn format_response(response: &serde_json::Value) -> jsonrpc_core::Result<serde_json::Value> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added this to produce the json string format that is required
container_api/src/interface.rs
Outdated
let id = Self::get_as_string("id", ¶ms_map)?; | ||
let path = Self::get_as_string("path", ¶ms_map)?; | ||
container_call!(|c| c.install_dna_from_file(PathBuf::from(path), id.to_string()))?; | ||
Self::format_response(&json!({"success": true})) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This produces a result as expected by hc-web-client/hc-redux-middleware and consistent with the other container functions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This all looks very good as an important initial step. I approve of it, but we need to keep track of the followups that come from it. The big one is the singleton issue. The small one is a quick decision on using https://docs.rs/directories/1.0.2/directories/struct.ProjectDirs.html for getting our project directory, and then implementing it sooner rather than later in a way that all parts of the code that want to put things there can make use of. I will put this in the tre...
file = "example-config/app_spec.hcpkg" | ||
hash = "Qm328wyq38924y" | ||
id = "app spec rust" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's not a big point but I think the name "app spec rust" is probably a little confusing here in the container crate, and we should just use something like "test-dna-instance-1" or something like that. Or even, as I read the example more, "instance-for-http-testing" and "intance-for-websocket-testing" because it looks like they are hooked up to different interfaces, and that would be semantically clearer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
.collect(); | ||
interface | ||
}) | ||
.collect(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice. I like retain!
@@ -73,10 +103,15 @@ impl Container { | |||
/// Creates a new instance with the default DnaLoader that actually loads files. | |||
pub fn from_config(config: Configuration) -> Self { | |||
let rules = config.logger.rules.clone(); | |||
let config_path = dirs::home_dir() | |||
.expect("No home dir defined. Don't know where to store config file") | |||
.join(std::path::PathBuf::from(".holochain/container-config.toml")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we probably should start using the directories crate project dir for storing these things. But I'll do that in a separate PR.
@@ -638,6 +708,29 @@ pub mod tests { | |||
container.stop_all_instances().unwrap(); | |||
} | |||
|
|||
//#[test] | |||
// Default config path ~/.holochain/container-config.toml won't work in CI |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
but it will if we use the directories crate...
container_api/src/container_admin.rs
Outdated
|
||
[logger] | ||
type = "" | ||
[[logger.rules.rules]] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm. I don't like that the default logger rules is being populated here when the default type isn't "debug" because the rules don't even apply if the type isn't "debug".. but this is a problem with the logger, not with this code...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to be here because the defaults get added when saving the config. So we need to add it to the fixture. I will post my 2nd PR on ContainerAdmin in a few minutes that includes a DRY out of these fixtures..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah probably but this indicates that we need to think through different default conditions. For running scenario tests, and end user probably wants the default logging just to show debug/dna
messages, and maybe err/*
For the container, the default is likely no debug messages. For us as holochain core devs, the default is what it currently is: All messages.
@@ -212,4 +409,24 @@ pub mod tests { | |||
assert!(result.contains(r#""happ-store/greeter/public/hello""#)); | |||
assert!(!result.contains(r#""test-instance-1//test/test""#)); | |||
} | |||
|
|||
/// The below test cannot be extented to test the other RPC methods due to the singleton design of the container |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm this speaks to the singleton problem, in that it's also an issue in our own container test code, not just the nodejs scenario tests....
# Conflicts: # container_api/src/error.rs
…into container-admin-functions
… with other admin functions
Format for all admin calls is not unstringified json and all holochain calls return just a string. I am happy now and will update hc-web-client/hc-redux-middleware |
@maackle I've implemented the refactoring we talked about. Visibility of Container structs is now restricted to a sub-module: pub struct Container {
instances: InstanceMap,
pub(in crate::container) instances: InstanceMap,
config: Configuration,
pub(in crate::container) config: Configuration,
interface_threads: HashMap<String, InterfaceThreadHandle>,
pub(in crate::container) config_path: PathBuf,
dna_loader: DnaLoader,
interface_threads: HashMap<String, Sender<()>>,
pub(in crate::container) dna_loader: DnaLoader, Please go ahead and merge if you approve :) |
That's kind of a cool pattern, module-level pub. As long as the module doesn't get huge. |
pub fn shutdown(&mut self) { | ||
let _ = self | ||
.stop_all_instances() | ||
.map_err(|error| notify(format!("Error during shutdown: {}", error))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why did we change the this from returning a result? stop_all_instances() seems to be mapping an error
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because if one instance errors during shutdown this function would exit early and not reset self.instances
.
Logically, shutdown should always work. If an instance complains when being shutdown, it should only show in the log.
@@ -246,8 +300,7 @@ impl Container { | |||
} | |||
|
|||
let config = self.config.clone(); | |||
self.shutdown().map_err(|e| e.to_string())?; | |||
self.instances = HashMap::new(); | |||
self.shutdown(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shutdown could propagate the error up here
Container Admin Functions (DNA/instance management)
Everything in grey is part of this PR:
Added container API functions
Which get added to an interface if
admin = true
.Prework / Refactoring
Had to make the container live in a static place so the interface threads can get a mutable reference for calling admin functions. Note though that I left this lazy_static! CONTAINER reference as something optional to use so tests and holochain_nodejs can own a Container instance and don't run into problems as @maackle pointed out..
Interfaces can now be shutdown which happens now in
Container::shutdown()
but not (yet !) between admin calls. We will need that to have changes (like new installed DNA) be reflected in the registered JSON RPC functions but I've left this as a follow-up since this PR starts to get big..Follow-ups
The big thing that is missing from this is updating interfaces after changes to the config. I almost added that to this PR already but want to think about a good solution first though. Easy catch would be to completely reload the config after any change but I think we can be more intelligent than that. I currently favor adding functions for handling interfaces (which we need anyway - like adding/removing interfaces and adding/removing instances from/to interfaces) and include a restart/update function there. Note that this would transfer responsibility for deciding when to update which interface over to the UI, i.e. HCadmin. (@zo-el, @JettTech)
File/storage management. Currently the path to the DNA file to be installed is left as it is and added to the config. I would like to have admin/dna/install_from_file copy the the DNA file into a managed directory (~/.holochain/dnas/, or that is /dnas). Next to that we could then also configure instances to have their storage in ~/.holochain/instances//storage (or /instance//storage) - currently the storage is hard-coded to memory (!).