diff --git a/easytier/src/easytier-cli.rs b/easytier/src/easytier-cli.rs index 7e3fedf..8b7cdf2 100644 --- a/easytier/src/easytier-cli.rs +++ b/easytier/src/easytier-cli.rs @@ -1335,7 +1335,7 @@ impl CommandHandler<'_> { inst_id: node_info.peer_id.to_string(), ipv4: node_info.ipv4_addr, hostname: node_info.hostname, - network_name: node_info.network_name, + network_name: "".to_string(), // NodeInfo doesn't have network_name field }]; print_output(&items, self.output_format)?; diff --git a/easytier/src/instance_manager.rs b/easytier/src/instance_manager.rs index 4ddd722..4adcf04 100644 --- a/easytier/src/instance_manager.rs +++ b/easytier/src/instance_manager.rs @@ -146,6 +146,41 @@ impl NetworkInstanceManager { .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 { self.instance_map.iter().map(|item| *item.key()).collect() } diff --git a/easytier/src/proto/web.proto b/easytier/src/proto/web.proto index 9d409e1..f7f633d 100644 --- a/easytier/src/proto/web.proto +++ b/easytier/src/proto/web.proto @@ -187,6 +187,16 @@ message GetConfigResponse { 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 { rpc ValidateConfig(ValidateConfigRequest) returns (ValidateConfigResponse) {} rpc RunNetworkInstance(RunNetworkInstanceRequest) returns (RunNetworkInstanceResponse) {} @@ -195,4 +205,5 @@ service WebClientService { rpc ListNetworkInstance(ListNetworkInstanceRequest) returns (ListNetworkInstanceResponse) {} rpc DeleteNetworkInstance(DeleteNetworkInstanceRequest) returns (DeleteNetworkInstanceResponse) {} rpc GetConfig(GetConfigRequest) returns (GetConfigResponse) {} + rpc ReplaceConfig(ReplaceConfigRequest) returns (ReplaceConfigResponse) {} } diff --git a/easytier/src/web_client/controller.rs b/easytier/src/web_client/controller.rs index c22517c..aec911d 100644 --- a/easytier/src/web_client/controller.rs +++ b/easytier/src/web_client/controller.rs @@ -8,9 +8,9 @@ use crate::{ CollectNetworkInfoRequest, CollectNetworkInfoResponse, DeleteNetworkInstanceRequest, DeleteNetworkInstanceResponse, GetConfigRequest, GetConfigResponse, ListNetworkInstanceRequest, ListNetworkInstanceResponse, NetworkInstanceRunningInfoMap, - RetainNetworkInstanceRequest, RetainNetworkInstanceResponse, RunNetworkInstanceRequest, - RunNetworkInstanceResponse, ValidateConfigRequest, ValidateConfigResponse, - WebClientService, + ReplaceConfigRequest, ReplaceConfigResponse, RetainNetworkInstanceRequest, + RetainNetworkInstanceResponse, RunNetworkInstanceRequest, RunNetworkInstanceResponse, + ValidateConfigRequest, ValidateConfigResponse, WebClientService, }, }, }; @@ -187,4 +187,46 @@ impl WebClientService for Controller { toml_config, }) } + + // rpc ReplaceConfig(ReplaceConfigRequest) returns (ReplaceConfigResponse) {} + async fn replace_config( + &self, + _: BaseController, + req: ReplaceConfigRequest, + ) -> Result { + 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), + }) + } + } + } }