[WIP] Daemon & CLI
This commit is contained in:
parent
56aad3a023
commit
8b158108bb
100 changed files with 6519 additions and 1596 deletions
|
|
@ -1,42 +1,34 @@
|
|||
use crate::DaemonRuntime;
|
||||
use iota_ipc::{
|
||||
IpcErrorCode, LocalRequest, ResponseEnvelope, ResponseResult,
|
||||
};
|
||||
use crate::{DaemonRuntime, DaemonServices};
|
||||
use iota_ipc::{ExitIntent, IpcErrorCode, LocalRequest, ResponseEnvelope, ResponseResult};
|
||||
use iota_logger::{log, log_command};
|
||||
use iota_storage::users::user_manager;
|
||||
use iota_storage::util::config_util::modify_config;
|
||||
use mtp::codec::{CommunicationType, CommunicationValue};
|
||||
use omikron_connector::omikron_connection::OMIKRON_CONNECTION;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::daemon_state::ShutdownReason;
|
||||
use crate::daemon_state::{ShutdownReason, StartupPhase};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct CommandRouter {
|
||||
runtime: Arc<DaemonRuntime>,
|
||||
services: Arc<DaemonServices>,
|
||||
}
|
||||
|
||||
impl CommandRouter {
|
||||
pub fn new(runtime: Arc<DaemonRuntime>) -> Self {
|
||||
Self { runtime }
|
||||
pub fn new(runtime: Arc<DaemonRuntime>, services: Arc<DaemonServices>) -> Self {
|
||||
Self { runtime, services }
|
||||
}
|
||||
|
||||
pub async fn route(&self, request_id: u64, request: LocalRequest) -> ResponseEnvelope {
|
||||
log_command!("{:?}", request);
|
||||
let result = self.execute(request).await;
|
||||
ResponseEnvelope {
|
||||
request_id,
|
||||
result,
|
||||
}
|
||||
ResponseEnvelope { request_id, result }
|
||||
}
|
||||
|
||||
/// Parse a legacy console command string into a typed request.
|
||||
pub fn parse_console_command(line: &str) -> Option<LocalRequest> {
|
||||
let parts: Vec<&str> = line
|
||||
.trim_start_matches('/')
|
||||
.split_whitespace()
|
||||
.collect();
|
||||
let parts: Vec<&str> = line.trim_start_matches('/').split_whitespace().collect();
|
||||
match parts.as_slice() {
|
||||
["help"] => None,
|
||||
["tasks"] => Some(LocalRequest::ListTasks),
|
||||
|
|
@ -53,13 +45,33 @@ impl CommandRouter {
|
|||
["user", "list"] => Some(LocalRequest::ListUsers),
|
||||
["reconnect"] => Some(LocalRequest::ReconnectOmikron),
|
||||
["regenerate", "keys"] => Some(LocalRequest::RotateIotaIdentity),
|
||||
["reload"] | ["restart"] => Some(LocalRequest::RestartDaemon),
|
||||
["shutdown"] | ["stop"] => Some(LocalRequest::StopDaemon),
|
||||
["reload"] | ["restart"] => Some(LocalRequest::RequestProcessExit {
|
||||
intent: ExitIntent::Restart,
|
||||
}),
|
||||
["shutdown"] | ["stop"] => Some(LocalRequest::RequestProcessExit {
|
||||
intent: ExitIntent::Stop,
|
||||
}),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
async fn execute(&self, request: LocalRequest) -> ResponseResult {
|
||||
let needs_omikron = matches!(
|
||||
request,
|
||||
LocalRequest::CreateUser { .. }
|
||||
| LocalRequest::RemoveUser { .. }
|
||||
| LocalRequest::ReconnectOmikron
|
||||
| LocalRequest::RotateIotaIdentity
|
||||
);
|
||||
if needs_omikron && !self.services.omikron.is_connected().await {
|
||||
return ResponseResult::Error(
|
||||
if self.runtime.current_startup_phase() != StartupPhase::Ready {
|
||||
IpcErrorCode::NotReady
|
||||
} else {
|
||||
IpcErrorCode::OmikronUnavailable
|
||||
},
|
||||
);
|
||||
}
|
||||
match request {
|
||||
LocalRequest::GetStatus => {
|
||||
let phase = self.runtime.current_startup_phase();
|
||||
|
|
@ -95,10 +107,13 @@ impl CommandRouter {
|
|||
ResponseResult::Ok(users.join("\n"))
|
||||
}
|
||||
LocalRequest::CreateUser { username } => {
|
||||
match omikron_connector::user_ops::create_user(&username).await {
|
||||
(Some(user), _) => {
|
||||
ResponseResult::Ok(format!("Created user {}", user.user_id))
|
||||
}
|
||||
match omikron_connector::user_ops::create_user(
|
||||
self.services.omikron.as_ref(),
|
||||
&username,
|
||||
)
|
||||
.await
|
||||
{
|
||||
(Some(user), _) => ResponseResult::Ok(format!("Created user {}", user.user_id)),
|
||||
_ => ResponseResult::Error(IpcErrorCode::StorageFailure),
|
||||
}
|
||||
}
|
||||
|
|
@ -109,24 +124,46 @@ impl CommandRouter {
|
|||
};
|
||||
let message = CommunicationValue::new(CommunicationType::DeleteUser)
|
||||
.with_sender(user.user_id as u64);
|
||||
if let Err(_e) = OMIKRON_CONNECTION.send_message(&message).await {
|
||||
if let Err(_e) = self.services.omikron.send_message(&message).await {
|
||||
return ResponseResult::Error(IpcErrorCode::OmikronUnavailable);
|
||||
}
|
||||
user_manager::remove_user(user.user_id);
|
||||
ResponseResult::Ok(format!("Removed user {}", user.user_id))
|
||||
}
|
||||
LocalRequest::ReconnectOmikron => {
|
||||
OMIKRON_CONNECTION.reconnect().await;
|
||||
ResponseResult::Ok("Reconnected to Omikron server".into())
|
||||
}
|
||||
LocalRequest::ReconnectOmikron => match self.services.omikron.reconnect().await {
|
||||
Ok(()) => ResponseResult::Ok("Reconnected to Omikron server".into()),
|
||||
Err(_) => ResponseResult::Error(IpcErrorCode::OmikronUnavailable),
|
||||
},
|
||||
LocalRequest::RotateIotaIdentity => {
|
||||
modify_config(|config| {
|
||||
config.public_key = None;
|
||||
config.private_key = None;
|
||||
config.iota_id = None;
|
||||
});
|
||||
OMIKRON_CONNECTION.reconnect().await;
|
||||
ResponseResult::Ok("Key pair regenerated and Omikron reconnection requested".into())
|
||||
match self.services.omikron.reconnect().await {
|
||||
Ok(()) => ResponseResult::Ok(
|
||||
"Key pair regenerated and Omikron reconnection requested".into(),
|
||||
),
|
||||
Err(_) => ResponseResult::Error(IpcErrorCode::OmikronUnavailable),
|
||||
}
|
||||
}
|
||||
LocalRequest::RequestProcessExit { intent } => {
|
||||
if matches!(intent, ExitIntent::Restart)
|
||||
&& !matches!(
|
||||
crate::deployment::from_environment().supervisor,
|
||||
iota_ipc::SupervisorKind::Systemd | iota_ipc::SupervisorKind::IotaUi
|
||||
)
|
||||
{
|
||||
return ResponseResult::Error(IpcErrorCode::Conflict);
|
||||
}
|
||||
self.runtime.shutdown(match intent {
|
||||
ExitIntent::Stop => ShutdownReason::Stop,
|
||||
ExitIntent::Restart => ShutdownReason::Restart,
|
||||
});
|
||||
ResponseResult::Ok("process exit accepted".into())
|
||||
}
|
||||
LocalRequest::GetDaemonStatus => {
|
||||
ResponseResult::Ok(format!("{:?}", self.runtime.snapshot()))
|
||||
}
|
||||
LocalRequest::RestartDaemon => {
|
||||
self.runtime.shutdown(ShutdownReason::Restart);
|
||||
|
|
@ -140,10 +177,12 @@ impl CommandRouter {
|
|||
}
|
||||
|
||||
pub async fn ping(&self, seconds: u64) -> Result<String, String> {
|
||||
let response = OMIKRON_CONNECTION
|
||||
let response = self
|
||||
.services
|
||||
.omikron
|
||||
.await_response(
|
||||
&CommunicationValue::new(CommunicationType::Ping),
|
||||
Some(Duration::from_secs(seconds)),
|
||||
Duration::from_secs(seconds),
|
||||
)
|
||||
.await;
|
||||
match response {
|
||||
|
|
|
|||
Loading…
Reference in a new issue