mirror of
https://mirror.suhoan.cn/https://github.com/EasyTier/EasyTier.git
synced 2025-12-14 13:47:24 +08:00
Compare commits
2 Commits
copilot/fi
...
manage-con
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0d41253279 | ||
|
|
c09630006c |
@@ -21,7 +21,6 @@ pub mod global_ctx;
|
|||||||
pub mod ifcfg;
|
pub mod ifcfg;
|
||||||
pub mod netns;
|
pub mod netns;
|
||||||
pub mod network;
|
pub mod network;
|
||||||
pub mod os_info;
|
|
||||||
pub mod scoped_task;
|
pub mod scoped_task;
|
||||||
pub mod stats_manager;
|
pub mod stats_manager;
|
||||||
pub mod stun;
|
pub mod stun;
|
||||||
|
|||||||
@@ -1,206 +0,0 @@
|
|||||||
use std::fs;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
||||||
pub struct OsInfo {
|
|
||||||
pub os_type: String,
|
|
||||||
pub os_version: String,
|
|
||||||
pub arch: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl OsInfo {
|
|
||||||
pub fn collect() -> Self {
|
|
||||||
Self {
|
|
||||||
os_type: get_os_type(),
|
|
||||||
os_version: get_os_version(),
|
|
||||||
arch: get_arch(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_string(&self) -> String {
|
|
||||||
format!("{} {} ({})", self.os_type, self.os_version, self.arch)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for OsInfo {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
os_type: "Unknown".to_string(),
|
|
||||||
os_version: "Unknown".to_string(),
|
|
||||||
arch: "Unknown".to_string(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_os_type() -> String {
|
|
||||||
std::env::consts::OS.to_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_arch() -> String {
|
|
||||||
std::env::consts::ARCH.to_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
fn get_os_version() -> String {
|
|
||||||
// Try to read distribution information from common files
|
|
||||||
if let Ok(content) = fs::read_to_string("/etc/os-release") {
|
|
||||||
if let Some(pretty_name) = extract_value_from_os_release(&content, "PRETTY_NAME") {
|
|
||||||
return pretty_name;
|
|
||||||
}
|
|
||||||
if let Some(name) = extract_value_from_os_release(&content, "NAME") {
|
|
||||||
let version = extract_value_from_os_release(&content, "VERSION").unwrap_or_default();
|
|
||||||
return if version.is_empty() {
|
|
||||||
name
|
|
||||||
} else {
|
|
||||||
format!("{} {}", name, version)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback to /etc/lsb-release
|
|
||||||
if let Ok(content) = fs::read_to_string("/etc/lsb-release") {
|
|
||||||
if let Some(description) = extract_value_from_lsb_release(&content, "DISTRIB_DESCRIPTION") {
|
|
||||||
return description;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback to kernel version
|
|
||||||
if let Ok(content) = fs::read_to_string("/proc/version") {
|
|
||||||
if let Some(first_line) = content.lines().next() {
|
|
||||||
return first_line.to_string();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"Linux".to_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
fn get_os_version() -> String {
|
|
||||||
// On Windows, try to get version from registry or use a simple approach
|
|
||||||
// For now, use a simple fallback
|
|
||||||
"Windows".to_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
fn get_os_version() -> String {
|
|
||||||
// Try to get macOS version using system_profiler or sw_vers
|
|
||||||
if let Ok(output) = std::process::Command::new("sw_vers")
|
|
||||||
.arg("-productName")
|
|
||||||
.output()
|
|
||||||
{
|
|
||||||
if output.status.success() {
|
|
||||||
let product_name = String::from_utf8_lossy(&output.stdout).trim().to_string();
|
|
||||||
|
|
||||||
if let Ok(version_output) = std::process::Command::new("sw_vers")
|
|
||||||
.arg("-productVersion")
|
|
||||||
.output()
|
|
||||||
{
|
|
||||||
if version_output.status.success() {
|
|
||||||
let version = String::from_utf8_lossy(&version_output.stdout).trim().to_string();
|
|
||||||
return format!("{} {}", product_name, version);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return product_name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"macOS".to_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(any(target_os = "linux", target_os = "windows", target_os = "macos")))]
|
|
||||||
fn get_os_version() -> String {
|
|
||||||
std::env::consts::OS.to_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
fn extract_value_from_os_release(content: &str, key: &str) -> Option<String> {
|
|
||||||
for line in content.lines() {
|
|
||||||
if let Some(pos) = line.find('=') {
|
|
||||||
let (line_key, value) = line.split_at(pos);
|
|
||||||
if line_key == key {
|
|
||||||
let value = &value[1..]; // Skip the '='
|
|
||||||
// Remove quotes if present
|
|
||||||
let value = value.trim_matches('"').trim_matches('\'');
|
|
||||||
return Some(value.to_string());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
fn extract_value_from_lsb_release(content: &str, key: &str) -> Option<String> {
|
|
||||||
extract_value_from_os_release(content, key)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_os_info_collection() {
|
|
||||||
let os_info = OsInfo::collect();
|
|
||||||
|
|
||||||
// Basic checks that we get some meaningful information
|
|
||||||
assert!(!os_info.os_type.is_empty());
|
|
||||||
assert!(!os_info.arch.is_empty());
|
|
||||||
assert!(!os_info.os_version.is_empty());
|
|
||||||
|
|
||||||
println!("OS Info: {}", os_info.to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_os_info_default() {
|
|
||||||
let default_info = OsInfo::default();
|
|
||||||
assert_eq!(default_info.os_type, "Unknown");
|
|
||||||
assert_eq!(default_info.os_version, "Unknown");
|
|
||||||
assert_eq!(default_info.arch, "Unknown");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
#[test]
|
|
||||||
fn test_extract_value_from_os_release() {
|
|
||||||
let content = r#"NAME="Ubuntu"
|
|
||||||
VERSION="20.04.3 LTS (Focal Fossa)"
|
|
||||||
ID=ubuntu
|
|
||||||
ID_LIKE=debian
|
|
||||||
PRETTY_NAME="Ubuntu 20.04.3 LTS"
|
|
||||||
VERSION_ID="20.04"
|
|
||||||
HOME_URL="https://www.ubuntu.com/"
|
|
||||||
SUPPORT_URL="https://help.ubuntu.com/"
|
|
||||||
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
|
|
||||||
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
|
|
||||||
VERSION_CODENAME=focal
|
|
||||||
UBUNTU_CODENAME=focal"#;
|
|
||||||
|
|
||||||
assert_eq!(extract_value_from_os_release(content, "NAME"), Some("Ubuntu".to_string()));
|
|
||||||
assert_eq!(extract_value_from_os_release(content, "PRETTY_NAME"), Some("Ubuntu 20.04.3 LTS".to_string()));
|
|
||||||
assert_eq!(extract_value_from_os_release(content, "VERSION_ID"), Some("20.04".to_string()));
|
|
||||||
assert_eq!(extract_value_from_os_release(content, "NONEXISTENT"), None);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_os_info_integration_with_route_peer_info() {
|
|
||||||
use crate::proto::peer_rpc::RoutePeerInfo;
|
|
||||||
use std::time::SystemTime;
|
|
||||||
|
|
||||||
// Test that RoutePeerInfo can hold OS information
|
|
||||||
let os_info = OsInfo::collect();
|
|
||||||
let mut peer_info = RoutePeerInfo::new();
|
|
||||||
peer_info.os_info = Some(os_info.to_string());
|
|
||||||
peer_info.hostname = Some("test-node".to_string());
|
|
||||||
peer_info.peer_id = 12345;
|
|
||||||
peer_info.last_update = Some(SystemTime::now().into());
|
|
||||||
|
|
||||||
// Verify the OS info is stored correctly
|
|
||||||
assert!(peer_info.os_info.is_some());
|
|
||||||
assert!(peer_info.os_info.as_ref().unwrap().contains(&os_info.os_type));
|
|
||||||
assert!(peer_info.os_info.as_ref().unwrap().contains(&os_info.arch));
|
|
||||||
|
|
||||||
// Test conversion to CLI Route
|
|
||||||
let cli_route: crate::proto::cli::Route = peer_info.into();
|
|
||||||
assert!(cli_route.os_info.is_some());
|
|
||||||
assert!(cli_route.os_info.as_ref().unwrap().contains(&os_info.os_type));
|
|
||||||
|
|
||||||
println!("OS Info in Route: {:?}", cli_route.os_info);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -109,6 +109,8 @@ enum SubCommand {
|
|||||||
Stats(StatsArgs),
|
Stats(StatsArgs),
|
||||||
#[command(about = "manage logger configuration")]
|
#[command(about = "manage logger configuration")]
|
||||||
Logger(LoggerArgs),
|
Logger(LoggerArgs),
|
||||||
|
#[command(about = "manage network instance configuration")]
|
||||||
|
Config(ConfigArgs),
|
||||||
#[command(about = t!("core_clap.generate_completions").to_string())]
|
#[command(about = t!("core_clap.generate_completions").to_string())]
|
||||||
GenAutocomplete { shell: Shell },
|
GenAutocomplete { shell: Shell },
|
||||||
}
|
}
|
||||||
@@ -293,6 +295,23 @@ enum LoggerSubCommand {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Args, Debug)]
|
||||||
|
struct ConfigArgs {
|
||||||
|
#[command(subcommand)]
|
||||||
|
sub_command: Option<ConfigSubCommand>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Subcommand, Debug)]
|
||||||
|
enum ConfigSubCommand {
|
||||||
|
/// List network instances and their configurations
|
||||||
|
List,
|
||||||
|
/// Get configuration for a specific instance
|
||||||
|
Get {
|
||||||
|
#[arg(help = "Instance ID")]
|
||||||
|
inst_id: String,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Args, Debug)]
|
#[derive(Args, Debug)]
|
||||||
struct ServiceArgs {
|
struct ServiceArgs {
|
||||||
#[arg(short, long, default_value = env!("CARGO_PKG_NAME"), help = "service name")]
|
#[arg(short, long, default_value = env!("CARGO_PKG_NAME"), help = "service name")]
|
||||||
@@ -1286,6 +1305,68 @@ impl CommandHandler<'_> {
|
|||||||
}
|
}
|
||||||
Ok(ports)
|
Ok(ports)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn handle_config_list(&self) -> Result<(), Error> {
|
||||||
|
let client = self.get_peer_manager_client().await?;
|
||||||
|
let node_info = client
|
||||||
|
.show_node_info(BaseController::default(), ShowNodeInfoRequest::default())
|
||||||
|
.await?
|
||||||
|
.node_info
|
||||||
|
.ok_or(anyhow::anyhow!("node info not found"))?;
|
||||||
|
|
||||||
|
if self.verbose || *self.output_format == OutputFormat::Json {
|
||||||
|
println!("{}", serde_json::to_string_pretty(&node_info)?);
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(tabled::Tabled, serde::Serialize)]
|
||||||
|
struct ConfigTableItem {
|
||||||
|
#[tabled(rename = "Instance ID")]
|
||||||
|
inst_id: String,
|
||||||
|
#[tabled(rename = "Virtual IP")]
|
||||||
|
ipv4: String,
|
||||||
|
#[tabled(rename = "Hostname")]
|
||||||
|
hostname: String,
|
||||||
|
#[tabled(rename = "Network Name")]
|
||||||
|
network_name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
let items = vec![ConfigTableItem {
|
||||||
|
inst_id: node_info.peer_id.to_string(),
|
||||||
|
ipv4: node_info.ipv4_addr,
|
||||||
|
hostname: node_info.hostname,
|
||||||
|
network_name: "".to_string(), // NodeInfo doesn't have network_name field
|
||||||
|
}];
|
||||||
|
|
||||||
|
print_output(&items, self.output_format)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_config_get(&self, inst_id: &str) -> Result<(), Error> {
|
||||||
|
let client = self.get_peer_manager_client().await?;
|
||||||
|
let node_info = client
|
||||||
|
.show_node_info(BaseController::default(), ShowNodeInfoRequest::default())
|
||||||
|
.await?
|
||||||
|
.node_info
|
||||||
|
.ok_or(anyhow::anyhow!("node info not found"))?;
|
||||||
|
|
||||||
|
// Check if the requested instance ID matches the current node
|
||||||
|
if node_info.peer_id.to_string() != inst_id {
|
||||||
|
return Err(anyhow::anyhow!(
|
||||||
|
"Instance ID {} not found. Current instance ID is {}",
|
||||||
|
inst_id,
|
||||||
|
node_info.peer_id
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.verbose || *self.output_format == OutputFormat::Json {
|
||||||
|
println!("{}", serde_json::to_string_pretty(&node_info)?);
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("{}", node_info.config);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -2097,6 +2178,14 @@ async fn main() -> Result<(), Error> {
|
|||||||
handler.handle_logger_set(level).await?;
|
handler.handle_logger_set(level).await?;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
SubCommand::Config(config_args) => match &config_args.sub_command {
|
||||||
|
Some(ConfigSubCommand::List) | None => {
|
||||||
|
handler.handle_config_list().await?;
|
||||||
|
}
|
||||||
|
Some(ConfigSubCommand::Get { inst_id }) => {
|
||||||
|
handler.handle_config_get(inst_id).await?;
|
||||||
|
}
|
||||||
|
},
|
||||||
SubCommand::GenAutocomplete { shell } => {
|
SubCommand::GenAutocomplete { shell } => {
|
||||||
let mut cmd = Cli::command();
|
let mut cmd = Cli::command();
|
||||||
easytier::print_completions(shell, &mut cmd, "easytier-cli");
|
easytier::print_completions(shell, &mut cmd, "easytier-cli");
|
||||||
|
|||||||
@@ -140,6 +140,47 @@ impl NetworkInstanceManager {
|
|||||||
.and_then(|instance| instance.value().get_running_info())
|
.and_then(|instance| instance.value().get_running_info())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_network_config(&self, instance_id: &uuid::Uuid) -> Option<TomlConfigLoader> {
|
||||||
|
self.instance_map
|
||||||
|
.get(instance_id)
|
||||||
|
.map(|instance| instance.value().get_config())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn replace_network_config(
|
||||||
|
&self,
|
||||||
|
instance_id: &uuid::Uuid,
|
||||||
|
new_config: TomlConfigLoader,
|
||||||
|
) -> Result<(), anyhow::Error> {
|
||||||
|
let mut instance = self
|
||||||
|
.instance_map
|
||||||
|
.get_mut(instance_id)
|
||||||
|
.ok_or_else(|| anyhow::anyhow!("instance {} not found", instance_id))?;
|
||||||
|
|
||||||
|
// Stop the current instance if it's running
|
||||||
|
if instance.is_easytier_running() {
|
||||||
|
// Get the config source before stopping
|
||||||
|
let config_source = instance.get_config_source();
|
||||||
|
|
||||||
|
// Create a new instance with the new config
|
||||||
|
let mut new_instance = NetworkInstance::new(new_config, config_source);
|
||||||
|
|
||||||
|
// Start the new instance
|
||||||
|
new_instance.start()?;
|
||||||
|
|
||||||
|
// Replace the old instance with the new one
|
||||||
|
*instance = new_instance;
|
||||||
|
|
||||||
|
// Restart the instance task if needed
|
||||||
|
self.start_instance_task(*instance_id)?;
|
||||||
|
} else {
|
||||||
|
// If the instance is not running, just replace the config
|
||||||
|
let config_source = instance.get_config_source();
|
||||||
|
*instance = NetworkInstance::new(new_config, config_source);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn list_network_instance_ids(&self) -> Vec<uuid::Uuid> {
|
pub fn list_network_instance_ids(&self) -> Vec<uuid::Uuid> {
|
||||||
self.instance_map.iter().map(|item| *item.key()).collect()
|
self.instance_map.iter().map(|item| *item.key()).collect()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -460,6 +460,10 @@ impl NetworkInstance {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_config(&self) -> TomlConfigLoader {
|
||||||
|
self.config.clone()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_proxy_network_to_config(
|
pub fn add_proxy_network_to_config(
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ use tokio::{
|
|||||||
use crate::{
|
use crate::{
|
||||||
common::{
|
common::{
|
||||||
config::NetworkIdentity, constants::EASYTIER_VERSION, global_ctx::ArcGlobalCtx,
|
config::NetworkIdentity, constants::EASYTIER_VERSION, global_ctx::ArcGlobalCtx,
|
||||||
os_info::OsInfo, stun::StunInfoCollectorTrait, PeerId,
|
stun::StunInfoCollectorTrait, PeerId,
|
||||||
},
|
},
|
||||||
peers::route_trait::{Route, RouteInterfaceBox},
|
peers::route_trait::{Route, RouteInterfaceBox},
|
||||||
proto::{
|
proto::{
|
||||||
@@ -131,7 +131,6 @@ impl RoutePeerInfo {
|
|||||||
quic_port: None,
|
quic_port: None,
|
||||||
ipv6_addr: None,
|
ipv6_addr: None,
|
||||||
groups: Vec::new(),
|
groups: Vec::new(),
|
||||||
os_info: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,7 +174,6 @@ impl RoutePeerInfo {
|
|||||||
ipv6_addr: global_ctx.get_ipv6().map(|x| x.into()),
|
ipv6_addr: global_ctx.get_ipv6().map(|x| x.into()),
|
||||||
|
|
||||||
groups: global_ctx.get_acl_groups(my_peer_id),
|
groups: global_ctx.get_acl_groups(my_peer_id),
|
||||||
os_info: Some(OsInfo::collect().to_string()),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let need_update_periodically = if let Ok(Ok(d)) =
|
let need_update_periodically = if let Ok(Ok(d)) =
|
||||||
@@ -230,7 +228,6 @@ impl From<RoutePeerInfo> for crate::proto::cli::Route {
|
|||||||
path_latency_latency_first: None,
|
path_latency_latency_first: None,
|
||||||
|
|
||||||
ipv6_addr: val.ipv6_addr,
|
ipv6_addr: val.ipv6_addr,
|
||||||
os_info: val.os_info,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,7 +68,6 @@ message Route {
|
|||||||
optional int32 path_latency_latency_first = 14;
|
optional int32 path_latency_latency_first = 14;
|
||||||
|
|
||||||
common.Ipv6Inet ipv6_addr = 15;
|
common.Ipv6Inet ipv6_addr = 15;
|
||||||
optional string os_info = 16;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message PeerRoutePair {
|
message PeerRoutePair {
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ message RoutePeerInfo {
|
|||||||
optional common.Ipv6Inet ipv6_addr = 15;
|
optional common.Ipv6Inet ipv6_addr = 15;
|
||||||
|
|
||||||
repeated PeerGroupInfo groups = 16;
|
repeated PeerGroupInfo groups = 16;
|
||||||
optional string os_info = 17;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message PeerIdVersion {
|
message PeerIdVersion {
|
||||||
|
|||||||
@@ -178,6 +178,25 @@ message DeleteNetworkInstanceResponse {
|
|||||||
repeated common.UUID remain_inst_ids = 1;
|
repeated common.UUID remain_inst_ids = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message GetConfigRequest {
|
||||||
|
common.UUID inst_id = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetConfigResponse {
|
||||||
|
NetworkConfig config = 1;
|
||||||
|
string toml_config = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ReplaceConfigRequest {
|
||||||
|
common.UUID inst_id = 1;
|
||||||
|
NetworkConfig config = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ReplaceConfigResponse {
|
||||||
|
bool success = 1;
|
||||||
|
optional string error_msg = 2;
|
||||||
|
}
|
||||||
|
|
||||||
service WebClientService {
|
service WebClientService {
|
||||||
rpc ValidateConfig(ValidateConfigRequest) returns (ValidateConfigResponse) {}
|
rpc ValidateConfig(ValidateConfigRequest) returns (ValidateConfigResponse) {}
|
||||||
rpc RunNetworkInstance(RunNetworkInstanceRequest) returns (RunNetworkInstanceResponse) {}
|
rpc RunNetworkInstance(RunNetworkInstanceRequest) returns (RunNetworkInstanceResponse) {}
|
||||||
@@ -185,4 +204,6 @@ service WebClientService {
|
|||||||
rpc CollectNetworkInfo(CollectNetworkInfoRequest) returns (CollectNetworkInfoResponse) {}
|
rpc CollectNetworkInfo(CollectNetworkInfoRequest) returns (CollectNetworkInfoResponse) {}
|
||||||
rpc ListNetworkInstance(ListNetworkInstanceRequest) returns (ListNetworkInstanceResponse) {}
|
rpc ListNetworkInstance(ListNetworkInstanceRequest) returns (ListNetworkInstanceResponse) {}
|
||||||
rpc DeleteNetworkInstance(DeleteNetworkInstanceRequest) returns (DeleteNetworkInstanceResponse) {}
|
rpc DeleteNetworkInstance(DeleteNetworkInstanceRequest) returns (DeleteNetworkInstanceResponse) {}
|
||||||
|
rpc GetConfig(GetConfigRequest) returns (GetConfigResponse) {}
|
||||||
|
rpc ReplaceConfig(ReplaceConfigRequest) returns (ReplaceConfigResponse) {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,8 +6,9 @@ use crate::{
|
|||||||
rpc_types::{self, controller::BaseController},
|
rpc_types::{self, controller::BaseController},
|
||||||
web::{
|
web::{
|
||||||
CollectNetworkInfoRequest, CollectNetworkInfoResponse, DeleteNetworkInstanceRequest,
|
CollectNetworkInfoRequest, CollectNetworkInfoResponse, DeleteNetworkInstanceRequest,
|
||||||
DeleteNetworkInstanceResponse, ListNetworkInstanceRequest, ListNetworkInstanceResponse,
|
DeleteNetworkInstanceResponse, GetConfigRequest, GetConfigResponse,
|
||||||
NetworkInstanceRunningInfoMap, RetainNetworkInstanceRequest,
|
ListNetworkInstanceRequest, ListNetworkInstanceResponse, NetworkInstanceRunningInfoMap,
|
||||||
|
ReplaceConfigRequest, ReplaceConfigResponse, RetainNetworkInstanceRequest,
|
||||||
RetainNetworkInstanceResponse, RunNetworkInstanceRequest, RunNetworkInstanceResponse,
|
RetainNetworkInstanceResponse, RunNetworkInstanceRequest, RunNetworkInstanceResponse,
|
||||||
ValidateConfigRequest, ValidateConfigResponse, WebClientService,
|
ValidateConfigRequest, ValidateConfigResponse, WebClientService,
|
||||||
},
|
},
|
||||||
@@ -153,4 +154,79 @@ impl WebClientService for Controller {
|
|||||||
remain_inst_ids: remain_inst_ids.into_iter().map(Into::into).collect(),
|
remain_inst_ids: remain_inst_ids.into_iter().map(Into::into).collect(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// rpc GetConfig(GetConfigRequest) returns (GetConfigResponse) {}
|
||||||
|
async fn get_config(
|
||||||
|
&self,
|
||||||
|
_: BaseController,
|
||||||
|
req: GetConfigRequest,
|
||||||
|
) -> Result<GetConfigResponse, rpc_types::error::Error> {
|
||||||
|
let inst_id = req.inst_id.ok_or_else(|| {
|
||||||
|
rpc_types::error::Error::ExecutionError(
|
||||||
|
anyhow::anyhow!("instance_id is required").into(),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let config = self
|
||||||
|
.manager
|
||||||
|
.get_network_config(&inst_id.into())
|
||||||
|
.ok_or_else(|| {
|
||||||
|
rpc_types::error::Error::ExecutionError(
|
||||||
|
anyhow::anyhow!("instance {} not found", inst_id).into(),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
// Get the NetworkConfig from the instance
|
||||||
|
let network_config = crate::launcher::NetworkConfig::new_from_config(&config)?;
|
||||||
|
|
||||||
|
// Get the TOML config string
|
||||||
|
let toml_config = config.dump();
|
||||||
|
|
||||||
|
Ok(GetConfigResponse {
|
||||||
|
config: Some(network_config),
|
||||||
|
toml_config,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// rpc ReplaceConfig(ReplaceConfigRequest) returns (ReplaceConfigResponse) {}
|
||||||
|
async fn replace_config(
|
||||||
|
&self,
|
||||||
|
_: BaseController,
|
||||||
|
req: ReplaceConfigRequest,
|
||||||
|
) -> Result<ReplaceConfigResponse, rpc_types::error::Error> {
|
||||||
|
let inst_id = req.inst_id.ok_or_else(|| {
|
||||||
|
rpc_types::error::Error::ExecutionError(
|
||||||
|
anyhow::anyhow!("instance_id is required").into(),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let new_config = req.config.ok_or_else(|| {
|
||||||
|
rpc_types::error::Error::ExecutionError(anyhow::anyhow!("config is required").into())
|
||||||
|
})?;
|
||||||
|
|
||||||
|
// Generate the TomlConfigLoader from NetworkConfig
|
||||||
|
let new_toml_config = new_config.gen_config()?;
|
||||||
|
|
||||||
|
// Replace the configuration
|
||||||
|
match self
|
||||||
|
.manager
|
||||||
|
.replace_network_config(&inst_id.into(), new_toml_config)
|
||||||
|
{
|
||||||
|
Ok(()) => {
|
||||||
|
println!("instance {} config replaced successfully", inst_id);
|
||||||
|
Ok(ReplaceConfigResponse {
|
||||||
|
success: true,
|
||||||
|
error_msg: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
let error_msg = format!("Failed to replace config for instance {}: {}", inst_id, e);
|
||||||
|
eprintln!("{}", error_msg);
|
||||||
|
Ok(ReplaceConfigResponse {
|
||||||
|
success: false,
|
||||||
|
error_msg: Some(error_msg),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user