优化
This commit is contained in:
parent
75fd783bc0
commit
7d1310a002
@ -18,3 +18,4 @@ windows = { version = "0.48", features = ["Win32_Foundation", "Win32_Security",
|
||||
wmi = "0.15.2"
|
||||
regex = "1.11.1"
|
||||
chrono = "0.4.40"
|
||||
netuser-rs = { git = "https://github.com/secur30nly/netuser-rs.git"}
|
||||
|
||||
510
src/main.rs
510
src/main.rs
@ -20,6 +20,7 @@ use std::os::windows::process::CommandExt;
|
||||
use wmi::{COMLibrary, WMIConnection, Variant, FilterValue};
|
||||
use std::collections::HashMap;
|
||||
use regex;
|
||||
use netuser_rs;
|
||||
|
||||
fn is_admin() -> bool {
|
||||
unsafe {
|
||||
@ -143,7 +144,9 @@ struct VirtualMachine {
|
||||
struct IpInfo {
|
||||
mac_address: String,
|
||||
switch_name: String,
|
||||
ip_addresses: Vec<String>,
|
||||
ipv4_addresses: Vec<String>,
|
||||
ipv6_addresses: Vec<String>,
|
||||
fqdn: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
@ -151,7 +154,9 @@ struct NetworkAdapter {
|
||||
macaddress: String,
|
||||
vmid: String,
|
||||
switchname: String,
|
||||
ipaddresses: Vec<String>,
|
||||
ipv4_addresses: Vec<String>,
|
||||
ipv6_addresses: Vec<String>,
|
||||
fqdn: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
@ -183,49 +188,40 @@ fn variant_to_string(v: &Variant) -> Option<String> {
|
||||
}
|
||||
|
||||
async fn stop_vm(vmid: &str) -> Result<String> {
|
||||
let wmi_con = get_wmi_connection()?;
|
||||
|
||||
// 查询虚拟机
|
||||
let mut filters = HashMap::new();
|
||||
filters.insert("Name".to_string(), FilterValue::String(vmid.to_string()));
|
||||
let vms: Vec<HashMap<String, Variant>> = wmi_con.filtered_query(&filters)?;
|
||||
|
||||
if vms.is_empty() {
|
||||
return Ok("VM not found".to_string());
|
||||
}
|
||||
|
||||
// 使用PowerShell停止虚拟机,因为WMI库中exec_method实现有问题
|
||||
// 使用PowerShell的Stop-VM命令异步停止虚拟机
|
||||
// -Force参数确保强制关闭,类似于断电
|
||||
// 使用Start-Job在后台运行,不等待完成
|
||||
let output = Command::new("powershell.exe")
|
||||
.args(["-Command", &format!("$OutputEncoding = [System.Text.Encoding]::UTF8; Get-CimInstance -Namespace root\\virtualization\\v2 -ClassName Msvm_ComputerSystem -Filter \"Name = '{}'\" | Invoke-CimMethod -MethodName RequestStateChange -Arguments @{{RequestedState=3; Force=$true}}", vmid)])
|
||||
.args(["-Command", &format!("Get-VM -Id '{}' | Stop-VM -Force -Confirm:$false | Out-Null", vmid)])
|
||||
.output()?;
|
||||
|
||||
Ok(String::from_utf8_lossy(&output.stdout).to_string())
|
||||
if output.status.success() {
|
||||
Ok("已关机".to_string())
|
||||
} else {
|
||||
let error = String::from_utf8_lossy(&output.stderr);
|
||||
Ok(format!("关机失败: {}", error))
|
||||
}
|
||||
}
|
||||
|
||||
async fn start_vm(vmid: &str) -> Result<String> {
|
||||
let wmi_con = get_wmi_connection()?;
|
||||
|
||||
// 查询虚拟机
|
||||
let mut filters = HashMap::new();
|
||||
filters.insert("Name".to_string(), FilterValue::String(vmid.to_string()));
|
||||
let vms: Vec<HashMap<String, Variant>> = wmi_con.filtered_query(&filters)?;
|
||||
|
||||
if vms.is_empty() {
|
||||
return Ok("VM not found".to_string());
|
||||
}
|
||||
|
||||
// 使用PowerShell启动虚拟机,因为WMI库中exec_method实现有问题
|
||||
// 使用PowerShell的Start-VM命令异步启动虚拟机
|
||||
// 使用Start-Job在后台运行,不等待完成
|
||||
let output = Command::new("powershell.exe")
|
||||
.args(["-Command", &format!("$OutputEncoding = [System.Text.Encoding]::UTF8; Get-CimInstance -Namespace root\\virtualization\\v2 -ClassName Msvm_ComputerSystem -Filter \"Name = '{}'\" | Invoke-CimMethod -MethodName RequestStateChange -Arguments @{{RequestedState=2}}", vmid)])
|
||||
.args(["-Command", &format!("Get-VM -Id '{}' | Start-VM | Out-Null", vmid)])
|
||||
.output()?;
|
||||
|
||||
Ok(String::from_utf8_lossy(&output.stdout).to_string())
|
||||
if output.status.success() {
|
||||
Ok("已启动".to_string())
|
||||
} else {
|
||||
let error = String::from_utf8_lossy(&output.stderr);
|
||||
Ok(format!("启动失败: {}", error))
|
||||
}
|
||||
}
|
||||
|
||||
async fn list_vm_details(vmid: &str) -> Result<String> {
|
||||
let wmi_con = get_wmi_connection()?;
|
||||
|
||||
// 查询特定虚拟机
|
||||
// 查询虚拟机是否存在
|
||||
let mut filters = HashMap::new();
|
||||
filters.insert("Name".to_string(), FilterValue::String(vmid.to_string()));
|
||||
let vms: Vec<HashMap<String, Variant>> = wmi_con.filtered_query(&filters)?;
|
||||
@ -277,7 +273,7 @@ async fn list_vm() -> Result<String> {
|
||||
|
||||
// 获取内存大小
|
||||
let memory_mb = get_vm_memory(&wmi_con, &vm_id)?;
|
||||
|
||||
|
||||
// 创建VM对象
|
||||
vms.push(VirtualMachine {
|
||||
vmid: vm_id,
|
||||
@ -294,93 +290,287 @@ async fn list_vm() -> Result<String> {
|
||||
Ok(json)
|
||||
}
|
||||
|
||||
// 获取虚拟机网络信息
|
||||
fn get_vm_network_info(wmi_con: &WMIConnection, vm_id: &str) -> Result<IpInfo> {
|
||||
println!("获取VM {} 的网络信息", vm_id);
|
||||
fn get_vm_fqdn(wmi_con: &WMIConnection, vm_id: &str) -> Result<String> {
|
||||
// 查询虚拟机的运行状态
|
||||
let vm_query = format!("SELECT * FROM Msvm_ComputerSystem WHERE Name='{}'", vm_id);
|
||||
let vms: Vec<HashMap<String, Variant>> = wmi_con.raw_query(&vm_query)?;
|
||||
|
||||
// 查询网络适配器
|
||||
let net_query = format!("SELECT * FROM Msvm_SyntheticEthernetPortSettingData WHERE InstanceID LIKE '%{}%'", vm_id);
|
||||
let network_adapters: Vec<HashMap<String, Variant>> = wmi_con.raw_query(&net_query)?;
|
||||
|
||||
if network_adapters.is_empty() {
|
||||
println!("没有找到网络适配器");
|
||||
return Ok(IpInfo {
|
||||
mac_address: String::new(),
|
||||
switch_name: String::new(),
|
||||
ip_addresses: Vec::new(),
|
||||
});
|
||||
if vms.is_empty() {
|
||||
return Ok(String::new());
|
||||
}
|
||||
|
||||
// 获取第一个网络适配器信息
|
||||
let adapter = &network_adapters[0];
|
||||
let mac_address = adapter.get("Address").and_then(variant_to_string).unwrap_or_default();
|
||||
let switch_name = adapter.get("SwitchName").and_then(variant_to_string).unwrap_or_default();
|
||||
// 检查虚拟机是否正在运行
|
||||
let running = match vms[0].get("EnabledState") {
|
||||
Some(Variant::I2(2)) | Some(Variant::I4(2)) | Some(Variant::UI2(2)) => true,
|
||||
_ => false
|
||||
};
|
||||
|
||||
// 尝试获取IP地址
|
||||
let mut ip_addresses = Vec::new();
|
||||
if !running {
|
||||
return Ok(String::new());
|
||||
}
|
||||
|
||||
// 查询关联的IP配置
|
||||
if !mac_address.is_empty() {
|
||||
// 通过虚拟机的管理服务获取IP地址
|
||||
if is_uuid(vm_id) {
|
||||
// 首先获取GuestIntrinsicExchangeItems,可能包含IP地址
|
||||
let guestinfo_query = format!(
|
||||
"ASSOCIATORS OF {{Msvm_ComputerSystem.CreationClassName='Msvm_ComputerSystem',Name='{}'}} \
|
||||
WHERE AssocClass=Msvm_SystemDevice ResultClass=Msvm_KvpExchangeComponent",
|
||||
vm_id
|
||||
);
|
||||
// 获取Msvm_KvpExchangeComponent关联组件
|
||||
let kvp_query = format!(
|
||||
"ASSOCIATORS OF {{Msvm_ComputerSystem.CreationClassName='Msvm_ComputerSystem',Name='{}'}} \
|
||||
WHERE AssocClass=Msvm_SystemDevice ResultClass=Msvm_KvpExchangeComponent",
|
||||
vm_id
|
||||
);
|
||||
|
||||
let kvp_components: Vec<HashMap<String, Variant>> = wmi_con.raw_query(&kvp_query)?;
|
||||
|
||||
if kvp_components.is_empty() {
|
||||
return Ok(String::new());
|
||||
}
|
||||
|
||||
// 获取GuestIntrinsicExchangeItems属性
|
||||
if let Some(Variant::Array(exchange_items)) = kvp_components[0].get("GuestIntrinsicExchangeItems") {
|
||||
// 遍历XML字符串数组
|
||||
for item in exchange_items {
|
||||
if let Variant::String(xml_str) = item {
|
||||
// 解析XML字符串,查找FullyQualifiedDomainName
|
||||
if xml_str.contains("FullyQualifiedDomainName") && xml_str.contains("<PROPERTY NAME=\"Data\"") {
|
||||
// 简单的XML解析,提取Data元素的值
|
||||
let data_start = xml_str.find("<PROPERTY NAME=\"Data\"");
|
||||
if let Some(start_pos) = data_start {
|
||||
let value_start = xml_str[start_pos..].find("<VALUE>");
|
||||
let value_end = xml_str[start_pos..].find("</VALUE>");
|
||||
|
||||
if let (Some(vs), Some(ve)) = (value_start, value_end) {
|
||||
let value_content = &xml_str[start_pos + vs + 7..start_pos + ve];
|
||||
if !value_content.trim().is_empty() {
|
||||
return Ok(value_content.trim().to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(String::new())
|
||||
}
|
||||
|
||||
// 获取虚拟机网络信息
|
||||
async fn get_vm_network_info(vm_id: Option<&str>) -> Result<String> {
|
||||
let wmi_con = get_wmi_connection()?;
|
||||
|
||||
match vm_id {
|
||||
Some(id) => {
|
||||
|
||||
let guest_info: Vec<HashMap<String, Variant>> = wmi_con.raw_query(&guestinfo_query)?;
|
||||
// 查询网络适配器
|
||||
let net_query = format!("SELECT * FROM Msvm_SyntheticEthernetPortSettingData WHERE InstanceID LIKE '%{}%'", id);
|
||||
let network_adapters: Vec<HashMap<String, Variant>> = wmi_con.raw_query(&net_query)?;
|
||||
|
||||
if !guest_info.is_empty() {
|
||||
// 解析GuestExchangeItems以获取IP地址
|
||||
if let Some(exchange_items) = guest_info[0].get("GuestExchangeItems").and_then(variant_to_string) {
|
||||
for line in exchange_items.lines() {
|
||||
if line.contains("NetworkAddressIPv4") || line.contains("NetworkAddressIPv6") {
|
||||
if let Some(ip) = line.split_whitespace().last() {
|
||||
if !ip.is_empty() && !ip_addresses.contains(&ip.to_string()) {
|
||||
ip_addresses.push(ip.to_string());
|
||||
if network_adapters.is_empty() {
|
||||
return Ok(serde_json::to_string(&serde_json::json!({
|
||||
"MacAddress": "",
|
||||
"SwitchName": "",
|
||||
"Ipv4Addresses": [],
|
||||
"Ipv6Addresses": [],
|
||||
"FQDN": "",
|
||||
"Running": false
|
||||
}))?);
|
||||
}
|
||||
|
||||
// 获取第一个网络适配器信息
|
||||
let adapter = &network_adapters[0];
|
||||
let mac_address = match adapter.get("Address") {
|
||||
Some(Variant::String(s)) => s.clone(),
|
||||
_ => String::new()
|
||||
};
|
||||
|
||||
|
||||
// 查询虚拟机状态
|
||||
let vm_query = format!("SELECT * FROM Msvm_ComputerSystem WHERE Name='{}'", id);
|
||||
let vms: Vec<HashMap<String, Variant>> = wmi_con.raw_query(&vm_query)?;
|
||||
|
||||
// 默认假设虚拟机未运行
|
||||
let mut running = false;
|
||||
|
||||
if !vms.is_empty() {
|
||||
let state = match vms[0].get("EnabledState") {
|
||||
Some(Variant::I2(2)) => 2,
|
||||
Some(Variant::I4(2)) => 2,
|
||||
Some(Variant::UI2(2)) => 2,
|
||||
_ => 0
|
||||
};
|
||||
running = state == 2;
|
||||
}
|
||||
|
||||
|
||||
// 尝试获取IP地址
|
||||
let mut ipv4_addresses = Vec::new();
|
||||
let mut ipv6_addresses = Vec::new();
|
||||
|
||||
// 获取FQDN
|
||||
let fqdn = get_vm_fqdn(&wmi_con, id)?;
|
||||
|
||||
// 只有虚拟机运行时才尝试获取IP地址
|
||||
if running && !mac_address.is_empty() {
|
||||
// 方法2: 查询所有Msvm_GuestNetworkAdapterConfiguration,尝试匹配VM ID或MAC地址
|
||||
let mac_no_colon = mac_address.replace(":", "");
|
||||
let all_ip_query = "SELECT * FROM Msvm_GuestNetworkAdapterConfiguration";
|
||||
|
||||
let all_ip_configs: Vec<HashMap<String, Variant>> = match wmi_con.raw_query(all_ip_query) {
|
||||
Ok(configs) => {
|
||||
configs
|
||||
},
|
||||
Err(e) => {
|
||||
Vec::new()
|
||||
}
|
||||
};
|
||||
|
||||
for config in &all_ip_configs {
|
||||
if let Some(Variant::String(instance_id)) = config.get("InstanceID") {
|
||||
// 如果ID包含VM ID或MAC地址,则提取IP
|
||||
if instance_id.contains(id) || instance_id.contains(&mac_no_colon) {
|
||||
|
||||
// 获取IP地址并分类
|
||||
if let Some(Variant::Array(addresses)) = config.get("IPAddresses") {
|
||||
for address in addresses {
|
||||
if let Variant::String(ip) = address {
|
||||
if !ip.is_empty() {
|
||||
// 判断是IPv4还是IPv6
|
||||
if ip.contains(':') {
|
||||
// IPv6
|
||||
let already_exists = ipv6_addresses.iter().any(|existing: &String| existing == ip);
|
||||
if !already_exists {
|
||||
ipv6_addresses.push(ip.clone());
|
||||
}
|
||||
} else {
|
||||
// IPv4
|
||||
let already_exists = ipv4_addresses.iter().any(|existing: &String| existing == ip);
|
||||
if !already_exists {
|
||||
ipv4_addresses.push(ip.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 如果上面方法没有找到IP,尝试其他方式
|
||||
if ip_addresses.is_empty() {
|
||||
// 尝试查询连接到具体网络适配器的IP地址信息
|
||||
let ip_query = format!(
|
||||
"SELECT * FROM Msvm_GuestNetworkAdapterConfiguration \
|
||||
WHERE InstanceID LIKE '%{}%'",
|
||||
mac_address.replace(":", "")
|
||||
);
|
||||
|
||||
let ip_configs: Vec<HashMap<String, Variant>> = wmi_con.raw_query(&ip_query)?;
|
||||
// 构建结果JSON
|
||||
let result = serde_json::json!({
|
||||
"MacAddress": mac_address,
|
||||
"ipv4": ipv4_addresses,
|
||||
"ipv6": ipv6_addresses,
|
||||
"FQDN": fqdn,
|
||||
});
|
||||
|
||||
if !ip_configs.is_empty() {
|
||||
// 尝试从IPAddresses获取IP
|
||||
if let Some(Variant::Array(ip_array)) = ip_configs[0].get("IPAddresses") {
|
||||
for ip_var in ip_array {
|
||||
if let Some(ip) = variant_to_string(ip_var) {
|
||||
if !ip.is_empty() && !ip_addresses.contains(&ip) {
|
||||
ip_addresses.push(ip);
|
||||
Ok(serde_json::to_string(&result)?)
|
||||
},
|
||||
None => {
|
||||
println!("获取所有VM的网络信息");
|
||||
|
||||
// 获取所有虚拟机
|
||||
let vm_query = "SELECT * FROM Msvm_ComputerSystem WHERE Caption='虚拟机' OR Caption='Virtual Machine'";
|
||||
let vms: Vec<HashMap<String, Variant>> = wmi_con.raw_query(vm_query)?;
|
||||
|
||||
let mut results = Vec::new();
|
||||
|
||||
for vm in &vms {
|
||||
let vm_id = match vm.get("Name") {
|
||||
Some(Variant::String(s)) => s.clone(),
|
||||
_ => continue
|
||||
};
|
||||
|
||||
let vm_name = match vm.get("ElementName") {
|
||||
Some(Variant::String(s)) => s.clone(),
|
||||
_ => String::new()
|
||||
};
|
||||
|
||||
// 获取虚拟机状态
|
||||
let running = match vm.get("EnabledState") {
|
||||
Some(Variant::I2(2)) | Some(Variant::I4(2)) | Some(Variant::UI2(2)) => true,
|
||||
_ => false
|
||||
};
|
||||
|
||||
// 查询网络适配器
|
||||
let net_query = format!("SELECT * FROM Msvm_SyntheticEthernetPortSettingData WHERE InstanceID LIKE '%{}%'", vm_id);
|
||||
let network_adapters: Vec<HashMap<String, Variant>> = wmi_con.raw_query(&net_query)?;
|
||||
|
||||
for adapter in &network_adapters {
|
||||
let mac_address = match adapter.get("Address") {
|
||||
Some(Variant::String(s)) => s.clone(),
|
||||
_ => String::new()
|
||||
};
|
||||
|
||||
let switch_name = match adapter.get("SwitchName") {
|
||||
Some(Variant::String(s)) => s.clone(),
|
||||
_ => String::new()
|
||||
};
|
||||
|
||||
// 尝试获取IP地址
|
||||
let mut ipv4_addresses = Vec::new();
|
||||
let mut ipv6_addresses = Vec::new();
|
||||
|
||||
// 获取FQDN
|
||||
let fqdn = get_vm_fqdn(&wmi_con, &vm_id)?;
|
||||
|
||||
if running && !mac_address.is_empty() {
|
||||
// 方法2: 尝试查询所有配置
|
||||
let mac_no_colon = mac_address.replace(":", "");
|
||||
let all_ip_query = "SELECT * FROM Msvm_GuestNetworkAdapterConfiguration";
|
||||
|
||||
let all_ip_configs: Vec<HashMap<String, Variant>> = match wmi_con.raw_query(all_ip_query) {
|
||||
Ok(configs) => configs,
|
||||
Err(_) => Vec::new()
|
||||
};
|
||||
|
||||
for config in &all_ip_configs {
|
||||
if let Some(Variant::String(instance_id)) = config.get("InstanceID") {
|
||||
if instance_id.contains(&vm_id) || instance_id.contains(&mac_no_colon) {
|
||||
// 获取IP地址并分类
|
||||
if let Some(Variant::Array(addresses)) = config.get("IPAddresses") {
|
||||
for address in addresses {
|
||||
if let Variant::String(ip) = address {
|
||||
if !ip.is_empty() {
|
||||
// 判断是IPv4还是IPv6
|
||||
if ip.contains(':') {
|
||||
// IPv6
|
||||
let already_exists = ipv6_addresses.iter().any(|existing: &String| existing == ip);
|
||||
if !already_exists {
|
||||
ipv6_addresses.push(ip.clone());
|
||||
}
|
||||
} else {
|
||||
// IPv4
|
||||
let already_exists = ipv4_addresses.iter().any(|existing: &String| existing == ip);
|
||||
if !already_exists {
|
||||
ipv4_addresses.push(ip.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 构建结果
|
||||
let result = serde_json::json!({
|
||||
"VmId": vm_id,
|
||||
"VmName": vm_name,
|
||||
"MacAddress": mac_address,
|
||||
"SwitchName": switch_name,
|
||||
"Ipv4Addresses": ipv4_addresses,
|
||||
"Ipv6Addresses": ipv6_addresses,
|
||||
"FQDN": fqdn,
|
||||
"Running": running
|
||||
});
|
||||
|
||||
results.push(result);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(serde_json::to_string(&results)?)
|
||||
}
|
||||
}
|
||||
|
||||
println!("网络信息: MAC={}, Switch={}, IPs={:?}", mac_address, switch_name, ip_addresses);
|
||||
|
||||
Ok(IpInfo {
|
||||
mac_address,
|
||||
switch_name,
|
||||
ip_addresses,
|
||||
})
|
||||
}
|
||||
|
||||
// 获取虚拟机CPU核心数
|
||||
@ -416,29 +606,6 @@ fn get_vm_cpu_cores(wmi_con: &WMIConnection, vm_id: &str) -> Result<u32> {
|
||||
// 获取虚拟机内存大小(MB)
|
||||
fn get_vm_memory(wmi_con: &WMIConnection, vm_id: &str) -> Result<u64> {
|
||||
|
||||
// 方法1: 通过内存设置关联查询
|
||||
let query1 = format!(
|
||||
"ASSOCIATORS OF {{Msvm_ComputerSystem.CreationClassName='Msvm_ComputerSystem',Name='{}'}} \
|
||||
WHERE AssocClass=Msvm_SettingsDefineState ResultClass=Msvm_MemorySettingData",
|
||||
vm_id
|
||||
);
|
||||
|
||||
let memory_settings1: Vec<HashMap<String, Variant>> = wmi_con.raw_query(&query1)?;
|
||||
|
||||
if !memory_settings1.is_empty() {
|
||||
// 从VirtualQuantity获取内存大小(MB)
|
||||
if let Some(mem) = memory_settings1[0].get("VirtualQuantity") {
|
||||
match mem {
|
||||
Variant::I4(mem) => return Ok(*mem as u64),
|
||||
Variant::UI4(mem) => return Ok(*mem as u64),
|
||||
Variant::I8(mem) => return Ok(*mem as u64),
|
||||
Variant::UI8(mem) => return Ok(*mem),
|
||||
_ => println!("方法1: 内存大小类型不匹配: {:?}", mem),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 方法2: 尝试直接查询内存设置
|
||||
let query2 = format!(
|
||||
"SELECT * FROM Msvm_MemorySettingData WHERE InstanceID LIKE '%{}%'",
|
||||
vm_id
|
||||
@ -458,26 +625,6 @@ fn get_vm_memory(wmi_con: &WMIConnection, vm_id: &str) -> Result<u64> {
|
||||
}
|
||||
}
|
||||
|
||||
// 方法3: 查询虚拟机配置
|
||||
let query3 = format!(
|
||||
"SELECT * FROM Msvm_VirtualSystemSettingData WHERE InstanceID LIKE '%{}%'",
|
||||
vm_id
|
||||
);
|
||||
|
||||
let vm_settings: Vec<HashMap<String, Variant>> = wmi_con.raw_query(&query3)?;
|
||||
|
||||
if !vm_settings.is_empty() {
|
||||
if let Some(mem) = vm_settings[0].get("MemoryStartup") {
|
||||
match mem {
|
||||
Variant::I4(mem) => return Ok(*mem as u64),
|
||||
Variant::UI4(mem) => return Ok(*mem as u64),
|
||||
Variant::I8(mem) => return Ok(*mem as u64),
|
||||
Variant::UI8(mem) => return Ok(*mem),
|
||||
_ => println!("方法3: 内存大小类型不匹配: {:?}", mem),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 默认返回1GB
|
||||
println!("无法确定内存大小,使用默认值: 1024MB");
|
||||
Ok(1024)
|
||||
@ -527,55 +674,6 @@ async fn get_all() -> Result<String> {
|
||||
Ok(json)
|
||||
}
|
||||
|
||||
async fn get_network(vmid: Option<&str>) -> Result<String> {
|
||||
let wmi_con = get_wmi_connection()?;
|
||||
|
||||
let mut adapters = Vec::new();
|
||||
|
||||
// 根据是否有VMID选择查询方式
|
||||
if let Some(id) = vmid {
|
||||
// 先获取特定虚拟机
|
||||
let mut vm_filters = HashMap::new();
|
||||
vm_filters.insert("Name".to_string(), FilterValue::String(id.to_string()));
|
||||
let vms: Vec<HashMap<String, Variant>> = wmi_con.filtered_query(&vm_filters)?;
|
||||
|
||||
if !vms.is_empty() {
|
||||
// 查询该虚拟机的网络适配器
|
||||
let wql = format!("SELECT * FROM Msvm_SyntheticEthernetPortSettingData WHERE InstanceID LIKE '%{}%'", id);
|
||||
let network_adapters: Vec<HashMap<String, Variant>> = wmi_con.raw_query(&wql)?;
|
||||
|
||||
for adapter in network_adapters {
|
||||
adapters.push(NetworkAdapter {
|
||||
macaddress: adapter.get("Address").and_then(variant_to_string).unwrap_or_default(),
|
||||
vmid: id.to_string(),
|
||||
switchname: adapter.get("SwitchName").and_then(variant_to_string).unwrap_or_default(),
|
||||
ipaddresses: Vec::new(), // WMI中不直接提供IP地址,需要额外查询
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 查询所有网络适配器
|
||||
let adapters_result: Vec<HashMap<String, Variant>> = wmi_con.query()?;
|
||||
|
||||
for adapter in adapters_result {
|
||||
// 从实例ID中提取VMID
|
||||
let instance_id = adapter.get("InstanceID").and_then(variant_to_string).unwrap_or_default();
|
||||
let vmid = extract_uuid_from_instance_id(&instance_id);
|
||||
|
||||
adapters.push(NetworkAdapter {
|
||||
macaddress: adapter.get("Address").and_then(variant_to_string).unwrap_or_default(),
|
||||
vmid,
|
||||
switchname: adapter.get("SwitchName").and_then(variant_to_string).unwrap_or_default(),
|
||||
ipaddresses: Vec::new(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 转换为JSON
|
||||
let json = serde_json::to_string(&adapters)?;
|
||||
Ok(json)
|
||||
}
|
||||
|
||||
// 从实例ID中提取UUID
|
||||
fn extract_uuid_from_instance_id(instance_id: &str) -> String {
|
||||
let re_str = r"\{[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\}";
|
||||
@ -693,7 +791,7 @@ async fn get_network_handler(query: web::Query<std::collections::HashMap<String,
|
||||
}
|
||||
|
||||
let vmid = query.get("VMID").map(|s| s.as_str());
|
||||
match get_network(vmid).await {
|
||||
match get_vm_network_info(vmid).await {
|
||||
Ok(result) => HttpResponse::Ok().body(result),
|
||||
Err(_) => HttpResponse::InternalServerError().json(serde_json::json!({ "error": "Failed to get network details" })),
|
||||
}
|
||||
@ -838,20 +936,28 @@ async fn generate_vm_ticket(_vmid: &str) -> Result<(String, String)> {
|
||||
}
|
||||
let password: String = password_chars.into_iter().collect();
|
||||
|
||||
// 创建临时用户并添加到Hyper-V管理员组,一分钟后自动删除
|
||||
let create_user_cmd = format!(
|
||||
"New-LocalUser -Name '{}' -Password (ConvertTo-SecureString '{}' -AsPlainText -Force) -Description 'Temporary Hyper-V access'; Add-LocalGroupMember -Group 'Hyper-V Administrators' -Member '{}'; Start-Job -ScriptBlock {{ Start-Sleep -Seconds 60; Remove-LocalUser -Name '{}' }}",
|
||||
username, password, username, username
|
||||
);
|
||||
// 使用netuser_rs库创建临时用户并添加到Hyper-V管理员组
|
||||
let description = Some("Temporary Hyper-V access user".to_string());
|
||||
|
||||
let output = Command::new("powershell.exe")
|
||||
.args(["-Command", &create_user_cmd])
|
||||
.output()?;
|
||||
|
||||
if !output.status.success() {
|
||||
anyhow::bail!("Failed to create temporary user: {}", String::from_utf8_lossy(&output.stderr));
|
||||
// 创建用户
|
||||
if let Err(err) = netuser_rs::users::add_user(&username, &password, &description) {
|
||||
anyhow::bail!("创建临时用户失败: {} - {}", err, netuser_rs::win_err_text(err));
|
||||
}
|
||||
|
||||
// 添加到Hyper-V管理员组
|
||||
if let Err(err) = netuser_rs::groups::add_user_to_group(&username, "Hyper-V Administrators") {
|
||||
// 如果添加到组失败,尝试删除用户
|
||||
let _ = netuser_rs::users::delete_user(&username);
|
||||
anyhow::bail!("添加用户到Hyper-V管理员组失败: {} - {}", err, netuser_rs::win_err_text(err));
|
||||
}
|
||||
|
||||
// 在后台启动线程60秒后删除用户
|
||||
let username_clone = username.clone();
|
||||
std::thread::spawn(move || {
|
||||
std::thread::sleep(std::time::Duration::from_secs(60));
|
||||
let _ = netuser_rs::users::delete_user(&username_clone);
|
||||
});
|
||||
|
||||
Ok((username, password))
|
||||
}
|
||||
|
||||
@ -897,7 +1003,7 @@ async fn main() -> std::io::Result<()> {
|
||||
.route("/api2/StopVM", web::post().to(stop_vm_handler))
|
||||
.route("/api2/StartVM", web::post().to(start_vm_handler))
|
||||
.route("/api2/ListVM", web::get().to(list_vm_handler))
|
||||
.route("/api2/getvmticket", web::get().to(get_vm_ticket_handler))
|
||||
.route("/api2/GetTicket", web::post().to(get_vm_ticket_handler))
|
||||
});
|
||||
|
||||
let server = if tls_enabled {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user