Node Health warnings (#5951)

* Health endpoint.

* Asynchronous health endpoint.

* Configure time api URL via CLI.

* Tests for TimeChecker.

* Health indication on Status page.

* Adding status indication to tab titles.

* Add status to ParityBar.

* Fixing lints.

* Add health status on SyncWarning.

* Fix health URL for embed.

* Nicer messages.

* Fix tests.

* Fixing JS tests.

* NTP time sync (#5956)

* use NTP to check time drift

* update time module documentation

* replace time_api flag with ntp_server

* fix TimeChecker tests

* fix ntp-server flag usage

* hide status tooltip if there's no message to show

* remove TimeProvider trait

* use Cell in FakeNtp test trait

* share fetch client and ntp client cpu pool

* Add documentation to public method.

* Removing peer count from status.

* Remove unknown upgrade status.

* Send two time requests at the time.

* Revert "Send two time requests at the time."

This reverts commit f7b754b1155076a5a5d8fdafa022801fae324452.

* Defer reporting time synchronization issues.

* Fix tests.

* Fix linting.
This commit is contained in:
Tomasz Drwięga
2017-07-11 12:23:46 +02:00
committed by Gav Wood
parent 7fb46bff06
commit 4936e99f30
48 changed files with 1296 additions and 125 deletions

View File

@@ -78,6 +78,7 @@ disable_periodic = true
jit = false
[misc]
ntp_server = "pool.ntp.org:123"
logging = "own_tx=trace"
log_file = "/var/log/parity.log"
color = true

View File

@@ -354,6 +354,8 @@ usage! {
or |c: &Config| otry!(c.vm).jit.clone(),
// -- Miscellaneous Options
flag_ntp_server: String = "pool.ntp.org:123",
or |c: &Config| otry!(c.misc).ntp_server.clone(),
flag_logging: Option<String> = None,
or |c: &Config| otry!(c.misc).logging.clone().map(Some),
flag_log_file: Option<String> = None,
@@ -590,6 +592,7 @@ struct VM {
#[derive(Default, Debug, PartialEq, Deserialize)]
struct Misc {
ntp_server: Option<String>,
logging: Option<String>,
log_file: Option<String>,
color: Option<bool>,
@@ -890,6 +893,7 @@ mod tests {
flag_dapps_apis_all: None,
// -- Miscellaneous Options
flag_ntp_server: "pool.ntp.org:123".into(),
flag_version: false,
flag_logging: Some("own_tx=trace".into()),
flag_log_file: Some("/var/log/parity.log".into()),
@@ -1066,6 +1070,7 @@ mod tests {
jit: Some(false),
}),
misc: Some(Misc {
ntp_server: Some("pool.ntp.org:123".into()),
logging: Some("own_tx=trace".into()),
log_file: Some("/var/log/parity.log".into()),
color: Some(true),

View File

@@ -467,6 +467,8 @@ Internal Options:
--can-restart Executable will auto-restart if exiting with 69.
Miscellaneous Options:
--ntp-server HOST NTP server to provide current time (host:port). Used to verify node health.
(default: {flag_ntp_server})
-l --logging LOGGING Specify the logging level. Must conform to the same
format as RUST_LOG. (default: {flag_logging:?})
--log-file FILENAME Specify a filename into which logging should be

View File

@@ -556,6 +556,7 @@ impl Configuration {
fn ui_config(&self) -> UiConfiguration {
UiConfiguration {
enabled: self.ui_enabled(),
ntp_server: self.args.flag_ntp_server.clone(),
interface: self.ui_interface(),
port: self.args.flag_ports_shift + self.args.flag_ui_port,
hosts: self.ui_hosts(),
@@ -565,6 +566,7 @@ impl Configuration {
fn dapps_config(&self) -> DappsConfiguration {
DappsConfiguration {
enabled: self.dapps_enabled(),
ntp_server: self.args.flag_ntp_server.clone(),
dapps_path: PathBuf::from(self.directories().dapps),
extra_dapps: if self.args.cmd_dapp {
self.args.arg_path.iter().map(|path| PathBuf::from(path)).collect()
@@ -1265,6 +1267,7 @@ mod tests {
support_token_api: true
}, UiConfiguration {
enabled: true,
ntp_server: "pool.ntp.org:123".into(),
interface: "127.0.0.1".into(),
port: 8180,
hosts: Some(vec![]),
@@ -1505,6 +1508,7 @@ mod tests {
assert_eq!(conf0.directories().signer, "signer".to_owned());
assert_eq!(conf0.ui_config(), UiConfiguration {
enabled: true,
ntp_server: "pool.ntp.org:123".into(),
interface: "127.0.0.1".into(),
port: 8180,
hosts: Some(vec![]),
@@ -1513,6 +1517,7 @@ mod tests {
assert_eq!(conf1.directories().signer, "signer".to_owned());
assert_eq!(conf1.ui_config(), UiConfiguration {
enabled: true,
ntp_server: "pool.ntp.org:123".into(),
interface: "127.0.0.1".into(),
port: 8180,
hosts: Some(vec![]),
@@ -1521,6 +1526,7 @@ mod tests {
assert_eq!(conf2.directories().signer, "signer".to_owned());
assert_eq!(conf2.ui_config(), UiConfiguration {
enabled: true,
ntp_server: "pool.ntp.org:123".into(),
interface: "127.0.0.1".into(),
port: 3123,
hosts: Some(vec![]),
@@ -1529,6 +1535,7 @@ mod tests {
assert_eq!(conf3.directories().signer, "signer".to_owned());
assert_eq!(conf3.ui_config(), UiConfiguration {
enabled: true,
ntp_server: "pool.ntp.org:123".into(),
interface: "test".into(),
port: 8180,
hosts: Some(vec![]),

View File

@@ -22,6 +22,7 @@ use ethcore::client::{Client, BlockChainClient, BlockId};
use ethcore::transaction::{Transaction, Action};
use ethsync::LightSync;
use futures::{future, IntoFuture, Future, BoxFuture};
use futures_cpupool::CpuPool;
use hash_fetch::fetch::Client as FetchClient;
use hash_fetch::urlhint::ContractClient;
use helpers::replace_home;
@@ -35,6 +36,7 @@ use util::{Bytes, Address};
#[derive(Debug, PartialEq, Clone)]
pub struct Configuration {
pub enabled: bool,
pub ntp_server: String,
pub dapps_path: PathBuf,
pub extra_dapps: Vec<PathBuf>,
}
@@ -44,6 +46,7 @@ impl Default for Configuration {
let data_dir = default_data_path();
Configuration {
enabled: true,
ntp_server: "pool.ntp.org:123".into(),
dapps_path: replace_home(&data_dir, "$BASE/dapps").into(),
extra_dapps: vec![],
}
@@ -140,6 +143,7 @@ pub struct Dependencies {
pub sync_status: Arc<SyncStatus>,
pub contract_client: Arc<ContractClient>,
pub remote: parity_reactor::TokioRemote,
pub pool: CpuPool,
pub fetch: FetchClient,
pub signer: Arc<SignerService>,
pub ui_address: Option<(String, u16)>,
@@ -152,20 +156,22 @@ pub fn new(configuration: Configuration, deps: Dependencies) -> Result<Option<Mi
server::dapps_middleware(
deps,
&configuration.ntp_server,
configuration.dapps_path,
configuration.extra_dapps,
rpc::DAPPS_DOMAIN.into(),
rpc::DAPPS_DOMAIN,
).map(Some)
}
pub fn new_ui(enabled: bool, deps: Dependencies) -> Result<Option<Middleware>, String> {
pub fn new_ui(enabled: bool, ntp_server: &str, deps: Dependencies) -> Result<Option<Middleware>, String> {
if !enabled {
return Ok(None);
}
server::ui_middleware(
deps,
rpc::DAPPS_DOMAIN.into(),
ntp_server,
rpc::DAPPS_DOMAIN,
).map(Some)
}
@@ -192,16 +198,18 @@ mod server {
pub fn dapps_middleware(
_deps: Dependencies,
_ntp_server: &str,
_dapps_path: PathBuf,
_extra_dapps: Vec<PathBuf>,
_dapps_domain: String,
_dapps_domain: &str,
) -> Result<Middleware, String> {
Err("Your Parity version has been compiled without WebApps support.".into())
}
pub fn ui_middleware(
_deps: Dependencies,
_dapps_domain: String,
_ntp_server: &str,
_dapps_domain: &str,
) -> Result<Middleware, String> {
Err("Your Parity version has been compiled without UI support.".into())
}
@@ -226,15 +234,18 @@ mod server {
pub fn dapps_middleware(
deps: Dependencies,
ntp_server: &str,
dapps_path: PathBuf,
extra_dapps: Vec<PathBuf>,
dapps_domain: String,
dapps_domain: &str,
) -> Result<Middleware, String> {
let signer = deps.signer;
let parity_remote = parity_reactor::Remote::new(deps.remote.clone());
let web_proxy_tokens = Arc::new(move |token| signer.web_proxy_access_token_domain(&token));
Ok(parity_dapps::Middleware::dapps(
ntp_server,
deps.pool,
parity_remote,
deps.ui_address,
dapps_path,
@@ -249,15 +260,18 @@ mod server {
pub fn ui_middleware(
deps: Dependencies,
dapps_domain: String,
ntp_server: &str,
dapps_domain: &str,
) -> Result<Middleware, String> {
let parity_remote = parity_reactor::Remote::new(deps.remote.clone());
Ok(parity_dapps::Middleware::ui(
ntp_server,
deps.pool,
parity_remote,
dapps_domain,
deps.contract_client,
deps.sync_status,
deps.fetch,
dapps_domain,
))
}

View File

@@ -29,6 +29,7 @@ extern crate docopt;
extern crate env_logger;
extern crate fdlimit;
extern crate futures;
extern crate futures_cpupool;
extern crate isatty;
extern crate jsonrpc_core;
extern crate num_cpus;

View File

@@ -74,6 +74,7 @@ impl Default for HttpConfiguration {
#[derive(Debug, PartialEq, Clone)]
pub struct UiConfiguration {
pub enabled: bool,
pub ntp_server: String,
pub interface: String,
pub port: u16,
pub hosts: Option<Vec<String>>,
@@ -107,6 +108,7 @@ impl Default for UiConfiguration {
fn default() -> Self {
UiConfiguration {
enabled: true && cfg!(feature = "ui-enabled"),
ntp_server: "pool.ntp.org:123".into(),
port: 8180,
interface: "127.0.0.1".into(),
hosts: Some(vec![]),

View File

@@ -27,8 +27,7 @@ use ethcore::miner::{StratumOptions, Stratum};
use ethcore::service::ClientService;
use ethcore::snapshot;
use ethcore::verification::queue::VerifierSettings;
use ethsync::NetworkConfiguration;
use ethsync::SyncConfig;
use ethsync::{self, SyncConfig};
use fdlimit::raise_fd_limit;
use hash_fetch::fetch::{Fetch, Client as FetchClient};
use informant::{Informant, LightNodeInformantData, FullNodeInformantData};
@@ -84,7 +83,7 @@ pub struct RunCmd {
pub ws_conf: rpc::WsConfiguration,
pub http_conf: rpc::HttpConfiguration,
pub ipc_conf: rpc::IpcConfiguration,
pub net_conf: NetworkConfiguration,
pub net_conf: ethsync::NetworkConfiguration,
pub network_id: Option<u64>,
pub warp_sync: bool,
pub public_node: bool,
@@ -237,7 +236,7 @@ fn execute_light(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) ->
network_config: net_conf.into_basic().map_err(|e| format!("Failed to produce network config: {}", e))?,
client: Arc::new(provider),
network_id: cmd.network_id.unwrap_or(spec.network_id()),
subprotocol_name: ::ethsync::LIGHT_PROTOCOL,
subprotocol_name: ethsync::LIGHT_PROTOCOL,
handlers: vec![on_demand.clone()],
};
let light_sync = LightSync::new(sync_params).map_err(|e| format!("Error starting network: {}", e))?;
@@ -277,9 +276,18 @@ fn execute_light(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) ->
on_demand: on_demand.clone(),
});
let sync = light_sync.clone();
struct LightSyncStatus(Arc<LightSync>);
impl dapps::SyncStatus for LightSyncStatus {
fn is_major_importing(&self) -> bool { self.0.is_major_importing() }
fn peers(&self) -> (usize, usize) {
let peers = ethsync::LightSyncProvider::peer_numbers(&*self.0);
(peers.connected, peers.max)
}
}
dapps::Dependencies {
sync_status: Arc::new(move || sync.is_major_importing()),
sync_status: Arc::new(LightSyncStatus(light_sync.clone())),
pool: fetch.pool(),
contract_client: contract_client,
remote: event_loop.raw_remote(),
fetch: fetch.clone(),
@@ -289,7 +297,7 @@ fn execute_light(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) ->
};
let dapps_middleware = dapps::new(cmd.dapps_conf.clone(), dapps_deps.clone())?;
let ui_middleware = dapps::new_ui(cmd.ui_conf.enabled, dapps_deps)?;
let ui_middleware = dapps::new_ui(cmd.ui_conf.enabled, &cmd.ui_conf.ntp_server, dapps_deps)?;
// start RPCs
let dapps_service = dapps::service(&dapps_middleware);
@@ -586,7 +594,7 @@ pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) -> R
let (sync_provider, manage_network, chain_notify) = modules::sync(
&mut hypervisor,
sync_config,
net_conf.into(),
net_conf.clone().into(),
client.clone(),
snapshot_service.clone(),
client.clone(),
@@ -630,8 +638,20 @@ pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) -> R
let (sync, client) = (sync_provider.clone(), client.clone());
let contract_client = Arc::new(::dapps::FullRegistrar { client: client.clone() });
struct SyncStatus(Arc<ethsync::SyncProvider>, Arc<Client>, ethsync::NetworkConfiguration);
impl dapps::SyncStatus for SyncStatus {
fn is_major_importing(&self) -> bool {
is_major_importing(Some(self.0.status().state), self.1.queue_info())
}
fn peers(&self) -> (usize, usize) {
let status = self.0.status();
(status.num_peers, status.current_max_peers(self.2.min_peers, self.2.max_peers) as usize)
}
}
dapps::Dependencies {
sync_status: Arc::new(move || is_major_importing(Some(sync.status().state), client.queue_info())),
sync_status: Arc::new(SyncStatus(sync, client, net_conf)),
pool: fetch.pool(),
contract_client: contract_client,
remote: event_loop.raw_remote(),
fetch: fetch.clone(),
@@ -640,7 +660,7 @@ pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) -> R
}
};
let dapps_middleware = dapps::new(cmd.dapps_conf.clone(), dapps_deps.clone())?;
let ui_middleware = dapps::new_ui(cmd.ui_conf.enabled, dapps_deps)?;
let ui_middleware = dapps::new_ui(cmd.ui_conf.enabled, &cmd.ui_conf.ntp_server, dapps_deps)?;
let dapps_service = dapps::service(&dapps_middleware);
let deps_for_rpc_apis = Arc::new(rpc_apis::FullDependencies {