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

Debug Conductor API #1661

Merged
merged 13 commits into from
Aug 20, 2019
8 changes: 8 additions & 0 deletions CHANGELOG-UNRELEASED.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm

### Added

* Conductor API debug functions added:
* `debug/running_instances`: returns array of running instance IDs
* `debug/state_dump`: returns a state dump for a given instance
* `debug/fetch_cas`: returns the content for a given entry address and instance ID

Also added the source to the state dump.
[#1661](https://github.com/holochain/holochain-rust/pull/1661)

### Changed

### Deprecated
Expand Down
3 changes: 2 additions & 1 deletion conductor_api/src/conductor/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1170,7 +1170,8 @@ impl Conductor {
conductor_api_builder = conductor_api_builder
.with_admin_dna_functions()
.with_admin_ui_functions()
.with_test_admin_functions();
.with_test_admin_functions()
.with_debug_functions();
}

conductor_api_builder.spawn()
Expand Down
34 changes: 34 additions & 0 deletions conductor_api/src/conductor/debug.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
use conductor::Conductor;
use holochain_core::state_dump::StateDump;
use holochain_core_types::error::HolochainError;
use holochain_persistence_api::cas::content::Address;

pub trait ConductorDebug {
fn running_instances(&self) -> Result<Vec<String>, HolochainError>;
fn state_dump_for_instance(&self, instance_id: &String) -> Result<StateDump, HolochainError>;
fn get_type_and_content_from_cas(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could use HcResult instead of Result here and several other places, but not terribly important.

&self,
address: &Address,
instance_id: &String,
) -> Result<(String, String), HolochainError>;
}

impl ConductorDebug for Conductor {
fn running_instances(&self) -> Result<Vec<String>, HolochainError> {
Ok(self.instances.keys().cloned().collect())
}

fn state_dump_for_instance(&self, instance_id: &String) -> Result<StateDump, HolochainError> {
let hc = self.instances.get(instance_id)?;
Ok(hc.read().unwrap().get_state_dump()?)
}

fn get_type_and_content_from_cas(
&self,
address: &Address,
instance_id: &String,
) -> Result<(String, String), HolochainError> {
let hc = self.instances.get(instance_id)?;
Ok(hc.read().unwrap().get_type_and_content_from_cas(address)?)
}
}
2 changes: 2 additions & 0 deletions conductor_api/src/conductor/mod.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
pub mod admin;
pub mod base;
pub mod broadcaster;
pub mod debug;
pub mod passphrase_manager;
pub mod test_admin;
pub mod ui_admin;

pub use self::{
admin::ConductorAdmin,
base::{mount_conductor_from_config, Conductor, CONDUCTOR},
debug::ConductorDebug,
test_admin::ConductorTestAdmin,
ui_admin::ConductorUiAdmin,
};
Expand Down
26 changes: 25 additions & 1 deletion conductor_api/src/holochain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,11 @@ use holochain_core_types::{

use holochain_json_api::json::JsonString;

use holochain_core::state::StateWrapper;
use holochain_core::{
state::StateWrapper,
state_dump::{address_to_content_and_type, StateDump},
};
use holochain_persistence_api::cas::content::Address;
use jsonrpc_core::IoHandler;
use std::sync::Arc;

Expand Down Expand Up @@ -263,6 +267,26 @@ impl Holochain {
self.context()?.conductor_api.reset(api);
Ok(())
}

pub fn get_state_dump(&self) -> Result<StateDump, HolochainInstanceError> {
self.check_instance()?;
Ok(StateDump::from(self.context.clone().expect(
"Context must be Some since we've checked it with check_instance()? above",
)))
}

pub fn get_type_and_content_from_cas(
&self,
address: &Address,
) -> Result<(String, String), HolochainInstanceError> {
self.check_instance()?;
Ok(address_to_content_and_type(
address,
self.context
.clone()
.expect("Context must be Some since we've checked it with check_instance()? above"),
)?)
}
}

#[cfg(test)]
Expand Down
55 changes: 54 additions & 1 deletion conductor_api/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use std::{
thread,
};

use conductor::{ConductorAdmin, ConductorTestAdmin, ConductorUiAdmin, CONDUCTOR};
use conductor::{ConductorAdmin, ConductorDebug, ConductorTestAdmin, ConductorUiAdmin, CONDUCTOR};
use config::{
AgentConfiguration, Bridge, DnaConfiguration, InstanceConfiguration, InterfaceConfiguration,
InterfaceDriver, UiBundleConfiguration, UiInterfaceConfiguration,
Expand Down Expand Up @@ -715,6 +715,59 @@ impl ConductorApiBuilder {
self
}

/// Adds functions useful for debugging.
///
/// - `debug/running_instances`
/// Get all currently running instances.
/// Returns an array of instance ID strings.
///
/// - `debug/state_dump`
/// Returns a JSON object with all relevant fields of an instance's state.
/// Params:
/// - `instance_id` ID of the instance of which the state is requested
///
/// - `debug/fetch_cas`
/// Returns content of a given instance's CAS.
/// Params:
/// - `instance_id` ID of the instance of which's CAS content is requested
/// - `address` Address (hash) of the content that is requests
/// Returns an object of the form: {type:"<entry type>", content: "<content>"}
///
pub fn with_debug_functions(mut self) -> Self {
self.io
.add_method("debug/running_instances", move |_params| {
let running_instances_ids = conductor_call!(|c| c.running_instances())?;
Ok(serde_json::to_value(running_instances_ids)
.map_err(|_| jsonrpc_core::Error::internal_error())?)
});

self.io.add_method("debug/state_dump", move |params| {
let params_map = Self::unwrap_params_map(params)?;
let instance_id = Self::get_as_string("instance_id", &params_map)?;

let dump = conductor_call!(|c| c.state_dump_for_instance(&instance_id))?;

Ok(serde_json::to_value(dump).map_err(|_| jsonrpc_core::Error::internal_error())?)
});

self.io.add_method("debug/fetch_cas", move |params| {
let params_map = Self::unwrap_params_map(params)?;
let instance_id = Self::get_as_string("instance_id", &params_map)?;
let address = Self::get_as_string("address", &params_map)?;

let (entry_type, content) = conductor_call!(
|c| c.get_type_and_content_from_cas(&Address::from(address), &instance_id)
)?;

Ok(json!({
"type": entry_type,
"content": content,
}))
});

self
}

/// Adds a further set of functions to the Conductor RPC for managing
/// static UI bundles and HTTP interfaces to these.
/// This adds the following RPC endpoints:
Expand Down
1 change: 1 addition & 0 deletions core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ pub mod persister;
pub mod scheduled_jobs;
pub mod signal;
pub mod state;
pub mod state_dump;
pub mod workflows;

mod conductor_api;
Loading