Compare commits

..

2 Commits

Author SHA1 Message Date
Sijie.Sun
a102a8bfc7 fix macos bind failed when addr is v6 (#1398) 2025-09-21 21:47:03 +08:00
Sijie.Sun
c9e8c35e77 fix log dir not work; fix stun config from file not work; (#1393) 2025-09-20 00:20:08 +08:00
8 changed files with 24 additions and 237 deletions

View File

@@ -109,8 +109,6 @@ enum SubCommand {
Stats(StatsArgs),
#[command(about = "manage logger configuration")]
Logger(LoggerArgs),
#[command(about = "manage network instance configuration")]
Config(ConfigArgs),
#[command(about = t!("core_clap.generate_completions").to_string())]
GenAutocomplete { shell: Shell },
}
@@ -295,23 +293,6 @@ 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)]
struct ServiceArgs {
#[arg(short, long, default_value = env!("CARGO_PKG_NAME"), help = "service name")]
@@ -1305,68 +1286,6 @@ impl CommandHandler<'_> {
}
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)]
@@ -2178,14 +2097,6 @@ async fn main() -> Result<(), Error> {
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 } => {
let mut cmd = Cli::command();
easytier::print_completions(shell, &mut cmd, "easytier-cli");

View File

@@ -968,8 +968,17 @@ impl NetworkOptions {
old_udp_whitelist.extend(self.udp_whitelist.clone());
cfg.set_udp_whitelist(old_udp_whitelist);
cfg.set_stun_servers(self.stun_servers.clone());
cfg.set_stun_servers_v6(self.stun_servers_v6.clone());
if let Some(stun_servers) = &self.stun_servers {
let mut old_stun_servers = cfg.get_stun_servers().unwrap_or_default();
old_stun_servers.extend(stun_servers.iter().cloned());
cfg.set_stun_servers(Some(old_stun_servers));
}
if let Some(stun_servers_v6) = &self.stun_servers_v6 {
let mut old_stun_servers_v6 = cfg.get_stun_servers_v6().unwrap_or_default();
old_stun_servers_v6.extend(stun_servers_v6.iter().cloned());
cfg.set_stun_servers_v6(Some(old_stun_servers_v6));
}
Ok(())
}
}

View File

@@ -140,47 +140,6 @@ impl NetworkInstanceManager {
.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> {
self.instance_map.iter().map(|item| *item.key()).collect()
}

View File

@@ -460,10 +460,6 @@ impl NetworkInstance {
None
}
}
pub fn get_config(&self) -> TomlConfigLoader {
self.config.clone()
}
}
pub fn add_proxy_network_to_config(

View File

@@ -178,25 +178,6 @@ message DeleteNetworkInstanceResponse {
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 {
rpc ValidateConfig(ValidateConfigRequest) returns (ValidateConfigResponse) {}
rpc RunNetworkInstance(RunNetworkInstanceRequest) returns (RunNetworkInstanceResponse) {}
@@ -204,6 +185,4 @@ service WebClientService {
rpc CollectNetworkInfo(CollectNetworkInfoRequest) returns (CollectNetworkInfoResponse) {}
rpc ListNetworkInstance(ListNetworkInstanceRequest) returns (ListNetworkInstanceResponse) {}
rpc DeleteNetworkInstance(DeleteNetworkInstanceRequest) returns (DeleteNetworkInstanceResponse) {}
rpc GetConfig(GetConfigRequest) returns (GetConfigResponse) {}
rpc ReplaceConfig(ReplaceConfigRequest) returns (ReplaceConfigResponse) {}
}

View File

@@ -384,7 +384,11 @@ pub(crate) fn setup_sokcet2_ext(
unsafe {
let dev_idx = nix::libc::if_nametoindex(dev_name.as_str().as_ptr() as *const i8);
tracing::warn!(?dev_idx, ?dev_name, "bind device");
socket2_socket.bind_device_by_index_v4(std::num::NonZeroU32::new(dev_idx))?;
if bind_addr.is_ipv4() {
socket2_socket.bind_device_by_index_v4(std::num::NonZeroU32::new(dev_idx))?;
} else {
socket2_socket.bind_device_by_index_v6(std::num::NonZeroU32::new(dev_idx))?;
}
tracing::warn!(?dev_idx, ?dev_name, "bind device doen");
}
}

View File

@@ -81,9 +81,14 @@ pub fn init_logger(
});
}
let dir = file_config.dir.as_deref().unwrap_or(".");
let file = file_config.file.as_deref().unwrap_or("easytier.log");
let path = std::path::Path::new(dir).join(file);
let path_str = path.to_string_lossy().into_owned();
let builder = RollingFileAppenderBase::builder();
let file_appender = builder
.filename(file_config.file.unwrap_or("easytier.log".to_string()))
.filename(path_str)
.condition_daily()
.max_filecount(file_config.count.unwrap_or(10))
.condition_max_file_size(file_config.size_mb.unwrap_or(100) * 1024 * 1024)

View File

@@ -6,9 +6,8 @@ use crate::{
rpc_types::{self, controller::BaseController},
web::{
CollectNetworkInfoRequest, CollectNetworkInfoResponse, DeleteNetworkInstanceRequest,
DeleteNetworkInstanceResponse, GetConfigRequest, GetConfigResponse,
ListNetworkInstanceRequest, ListNetworkInstanceResponse, NetworkInstanceRunningInfoMap,
ReplaceConfigRequest, ReplaceConfigResponse, RetainNetworkInstanceRequest,
DeleteNetworkInstanceResponse, ListNetworkInstanceRequest, ListNetworkInstanceResponse,
NetworkInstanceRunningInfoMap, RetainNetworkInstanceRequest,
RetainNetworkInstanceResponse, RunNetworkInstanceRequest, RunNetworkInstanceResponse,
ValidateConfigRequest, ValidateConfigResponse, WebClientService,
},
@@ -154,79 +153,4 @@ impl WebClientService for Controller {
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),
})
}
}
}
}