Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource;
import com.cloud.resource.CommandWrapper;
import com.cloud.resource.ResourceWrapper;
import com.cloud.utils.Pair;
import com.cloud.utils.net.NetUtils;
import com.cloud.utils.script.Script;

Expand All @@ -37,6 +38,26 @@ public final class LibvirtGetVmIpAddressCommandWrapper extends CommandWrapper<Ge

private static final Logger s_logger = Logger.getLogger(LibvirtGetVmIpAddressCommandWrapper.class);

static String virsh_path = null;
static String virt_win_reg_path = null;
static String grep_path = null;
static String awk_path = null;
static String sed_path = null;
static String virt_ls_path = null;
static String virt_cat_path = null;
static String tail_path = null;

static void init() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rg9975
the method is never used in LibvirtGetVmIpAddressCommandWrapper.java
which breaks the functionality

I will fix it in #10431

virt_ls_path = Script.getExecutableAbsolutePath("virt-ls");
virt_cat_path = Script.getExecutableAbsolutePath("virt-cat");
virt_win_reg_path = Script.getExecutableAbsolutePath("virt-win-reg");
tail_path = Script.getExecutableAbsolutePath("tail");
grep_path = Script.getExecutableAbsolutePath("grep");
awk_path = Script.getExecutableAbsolutePath("awk");
sed_path = Script.getExecutableAbsolutePath("sed");
virsh_path = Script.getExecutableAbsolutePath("virsh");
}

@Override
public Answer execute(final GetVmIpAddressCommand command, final LibvirtComputingResource libvirtComputingResource) {
String ip = null;
Expand All @@ -45,99 +66,113 @@ public Answer execute(final GetVmIpAddressCommand command, final LibvirtComputin
if (!NetUtils.verifyDomainNameLabel(vmName, true)) {
return new Answer(command, result, ip);
}

String sanitizedVmName = sanitizeBashCommandArgument(vmName);
String networkCidr = command.getVmNetworkCidr();
final String virt_ls_path = Script.getExecutableAbsolutePath("virt-ls");
final String virt_cat_path = Script.getExecutableAbsolutePath("virt-cat");
final String virt_win_reg_path = Script.getExecutableAbsolutePath("virt-win-reg");
final String tail_path = Script.getExecutableAbsolutePath("tail");
final String grep_path = Script.getExecutableAbsolutePath("grep");
final String awk_path = Script.getExecutableAbsolutePath("awk");
final String sed_path = Script.getExecutableAbsolutePath("sed");
final String virsh_path = Script.getExecutableAbsolutePath("virsh");

// first run virsh domiflist to get the network interface name from libvirt. This is set if qemu guest agent is running in the VM
// and is the most reliable and least intrusive

ip = ipFromDomIf(sanitizedVmName, networkCidr);

if (ip == null) {
if(!command.isWindows()) {
ip = ipFromDhcpLeaseFile(sanitizedVmName, networkCidr);
} else {
ip = ipFromWindowsRegistry(sanitizedVmName, networkCidr);
}
}

if(ip != null){
result = true;
s_logger.debug("GetVmIp: "+ vmName + " Found Ip: "+ip);
} else {
s_logger.warn("GetVmIp: "+ vmName + " IP not found.");
}

return new Answer(command, result, ip);
}

private String ipFromDomIf(String sanitizedVmName, String networkCidr) {
String ip = null;
List<String[]> commands = new ArrayList<>();
commands.add(new String[]{virsh_path, "domifaddr", sanitizedVmName, "--source", "agent"});
String output = Script.executePipedCommands(commands, 0).second();
if (output != null) {
Pair<Integer,String> response = executePipedCommands(commands, 0);
if (response != null) {
String output = response.second();
String[] lines = output.split("\n");
for (String line : lines) {
ip = parseDomIfListOutput(line, networkCidr);
if (ip != null) {
break;
if (line.contains("ipv4")) {
String[] parts = line.split(" ");
String[] ipParts = parts[parts.length-1].split("/");
if (ipParts.length > 1) {
if (NetUtils.isIpWithInCidrRange(ipParts[0], networkCidr)) {
ip = ipParts[0];
break;
}
}
}
}
} else {
s_logger.error("ipFromDomIf: Command execution failed for VM: " + sanitizedVmName);
}
return ip;
}

commands.clear();
commands.add(new String[]{grep_path, ".*\\*"});
if(ip == null && !command.isWindows()) {
//List all dhcp lease files inside guestVm
commands.add(new String[]{virt_ls_path, sanitizedVmName, "/var/lib/dhclient/"});
commands.add(new String[]{grep_path, ".*\\*.leases"});
String leasesList = Script.executePipedCommands(commands, 0).second();
if(leasesList != null) {
String[] leasesFiles = leasesList.split("\n");
for(String leaseFile : leasesFiles){
//Read from each dhclient lease file inside guest Vm using virt-cat libguestfs utility
commands = new ArrayList<>();
commands.add(new String[]{virt_cat_path, sanitizedVmName, "/var/lib/dhclient/" + leaseFile});
commands.add(new String[]{tail_path, "-16"});
commands.add(new String[]{grep_path, "fixed-address"});
commands.add(new String[]{awk_path, "{print $2}"});
commands.add(new String[]{sed_path, "-e", "s/;//"});
String ipAddr = Script.executePipedCommands(commands, 0).second();
// Check if the IP belongs to the network
if((ipAddr != null) && NetUtils.isIpWithInCidrRange(ipAddr, networkCidr)) {
ip = ipAddr;
break;
}
s_logger.debug("GetVmIp: "+ vmName + " Ip: "+ipAddr+" does not belong to network "+networkCidr);
private String ipFromDhcpLeaseFile(String sanitizedVmName, String networkCidr) {
String ip = null;
List<String[]> commands = new ArrayList<>();
commands.add(new String[]{virt_ls_path, sanitizedVmName, "/var/lib/dhclient/"});
commands.add(new String[]{grep_path, ".*\\*.leases"});
Pair<Integer,String> response = executePipedCommands(commands, 0);

if(response != null && response.second() != null) {
String leasesList = response.second();
String[] leasesFiles = leasesList.split("\n");
for(String leaseFile : leasesFiles){
commands = new ArrayList<>();
commands.add(new String[]{virt_cat_path, sanitizedVmName, "/var/lib/dhclient/" + leaseFile});
commands.add(new String[]{tail_path, "-16"});
commands.add(new String[]{grep_path, "fixed-address"});
commands.add(new String[]{awk_path, "{print $2}"});
commands.add(new String[]{sed_path, "-e", "s/;//"});
String ipAddr = executePipedCommands(commands, 0).second();
if((ipAddr != null) && NetUtils.isIpWithInCidrRange(ipAddr, networkCidr)) {
ip = ipAddr;
break;
}
s_logger.debug("GetVmIp: "+ sanitizedVmName + " Ip: "+ipAddr+" does not belong to network "+networkCidr);
}
} else {
// For windows, read from guest Vm registry using virt-win-reg libguestfs ulitiy. Registry Path: HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\Tcpip\Parameters\Interfaces\<service>\DhcpIPAddress
commands = new ArrayList<>();
commands.add(new String[]{virt_win_reg_path, "--unsafe-printable-strings", sanitizedVmName, "HKEY_LOCAL_MACHINE\\SYSTEM\\ControlSet001\\Services\\Tcpip\\Parameters\\Interfaces"});
commands.add(new String[]{grep_path, "DhcpIPAddress"});
commands.add(new String[]{awk_path, "-F", ":", "{print $2}"});
commands.add(new String[]{sed_path, "-e", "s/^\"//", "-e", "s/\"$//"});
String ipList = Script.executePipedCommands(commands, 0).second();
if(ipList != null) {
s_logger.debug("GetVmIp: "+ vmName + "Ips: "+ipList);
String[] ips = ipList.split("\n");
for (String ipAddr : ips){
// Check if the IP belongs to the network
if((ipAddr != null) && NetUtils.isIpWithInCidrRange(ipAddr, networkCidr)){
ip = ipAddr;
break;
}
s_logger.debug("GetVmIp: "+ vmName + " Ip: "+ipAddr+" does not belong to network "+networkCidr);
}
}
}
if(ip != null){
result = true;
s_logger.debug("GetVmIp: "+ vmName + " Found Ip: "+ip);
s_logger.error("ipFromDhcpLeaseFile: Command execution failed for VM: " + sanitizedVmName);
}
return new Answer(command, result, ip);
return ip;
}

private String parseDomIfListOutput(String line, String networkCidr) {
private String ipFromWindowsRegistry(String sanitizedVmName, String networkCidr) {
String ip = null;
if (line.contains("ipv4")) {
String[] parts = line.split(" ");
if (parts.length > 2) {
String[] ipParts = parts[2].split("/");
if (ipParts.length > 0) {
if (NetUtils.isIpWithInCidrRange(ipParts[0], networkCidr)) {
ip = ipParts[0];
}
List<String[]> commands = new ArrayList<>();
commands.add(new String[]{virt_win_reg_path, "--unsafe-printable-strings", sanitizedVmName, "HKEY_LOCAL_MACHINE\\SYSTEM\\ControlSet001\\Services\\Tcpip\\Parameters\\Interfaces"});
commands.add(new String[]{grep_path, "DhcpIPAddress"});
commands.add(new String[]{awk_path, "-F", ":", "{print $2}"});
commands.add(new String[]{sed_path, "-e", "s/^\"//", "-e", "s/\"$//"});
Pair<Integer,String> pair = executePipedCommands(commands, 0);
if(pair != null && pair.second() != null) {
String ipList = pair.second();
ipList = ipList.replaceAll("\"", "");
s_logger.debug("GetVmIp: "+ sanitizedVmName + "Ips: "+ipList);
String[] ips = ipList.split("\n");
for (String ipAddr : ips){
if((ipAddr != null) && NetUtils.isIpWithInCidrRange(ipAddr, networkCidr)){
ip = ipAddr;
break;
}
s_logger.debug("GetVmIp: "+ sanitizedVmName + " Ip: "+ipAddr+" does not belong to network "+networkCidr);
}
} else {
s_logger.error("ipFromWindowsRegistry: Command execution failed for VM: " + sanitizedVmName);
}
return ip;
}

static Pair<Integer, String> executePipedCommands(List<String[]> commands, long timeout) {
return Script.executePipedCommands(commands, timeout);
}
}
Loading
Loading