Skip to content

Commit f017985

Browse files
author
Rene Glover
authored
add use of virsh domifaddr to get VM external DHCP IP (apache#10376)
* add use of virsh domifaddr to get VM external DHCP IP * updates to modularize LibvirtGetVmIpAddressCommandWrapper per comments; added test cases to cover 90%+ scenarios * updates to modularize LibvirtGetVmIpAddressCommandWrapper per comments; added test cases to cover 90%+ scenarios * updates to modularize LibvirtGetVmIpAddressCommandWrapper per comments; added test cases to cover 90%+ scenarios
1 parent f992ebb commit f017985

File tree

2 files changed

+438
-49
lines changed

2 files changed

+438
-49
lines changed

plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetVmIpAddressCommandWrapper.java

Lines changed: 118 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource;
3030
import com.cloud.resource.CommandWrapper;
3131
import com.cloud.resource.ResourceWrapper;
32+
import com.cloud.utils.Pair;
3233
import com.cloud.utils.net.NetUtils;
3334
import com.cloud.utils.script.Script;
3435

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

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

41+
static String virsh_path = null;
42+
static String virt_win_reg_path = null;
43+
static String grep_path = null;
44+
static String awk_path = null;
45+
static String sed_path = null;
46+
static String virt_ls_path = null;
47+
static String virt_cat_path = null;
48+
static String tail_path = null;
49+
50+
static void init() {
51+
virt_ls_path = Script.getExecutableAbsolutePath("virt-ls");
52+
virt_cat_path = Script.getExecutableAbsolutePath("virt-cat");
53+
virt_win_reg_path = Script.getExecutableAbsolutePath("virt-win-reg");
54+
tail_path = Script.getExecutableAbsolutePath("tail");
55+
grep_path = Script.getExecutableAbsolutePath("grep");
56+
awk_path = Script.getExecutableAbsolutePath("awk");
57+
sed_path = Script.getExecutableAbsolutePath("sed");
58+
virsh_path = Script.getExecutableAbsolutePath("virsh");
59+
}
60+
4061
@Override
4162
public Answer execute(final GetVmIpAddressCommand command, final LibvirtComputingResource libvirtComputingResource) {
4263
String ip = null;
@@ -45,65 +66,113 @@ public Answer execute(final GetVmIpAddressCommand command, final LibvirtComputin
4566
if (!NetUtils.verifyDomainNameLabel(vmName, true)) {
4667
return new Answer(command, result, ip);
4768
}
69+
4870
String sanitizedVmName = sanitizeBashCommandArgument(vmName);
4971
String networkCidr = command.getVmNetworkCidr();
72+
73+
ip = ipFromDomIf(sanitizedVmName, networkCidr);
74+
75+
if (ip == null) {
76+
if(!command.isWindows()) {
77+
ip = ipFromDhcpLeaseFile(sanitizedVmName, networkCidr);
78+
} else {
79+
ip = ipFromWindowsRegistry(sanitizedVmName, networkCidr);
80+
}
81+
}
82+
83+
if(ip != null){
84+
result = true;
85+
s_logger.debug("GetVmIp: "+ vmName + " Found Ip: "+ip);
86+
} else {
87+
s_logger.warn("GetVmIp: "+ vmName + " IP not found.");
88+
}
89+
90+
return new Answer(command, result, ip);
91+
}
92+
93+
private String ipFromDomIf(String sanitizedVmName, String networkCidr) {
94+
String ip = null;
5095
List<String[]> commands = new ArrayList<>();
51-
final String virt_ls_path = Script.getExecutableAbsolutePath("virt-ls");
52-
final String virt_cat_path = Script.getExecutableAbsolutePath("virt-cat");
53-
final String virt_win_reg_path = Script.getExecutableAbsolutePath("virt-win-reg");
54-
final String tail_path = Script.getExecutableAbsolutePath("tail");
55-
final String grep_path = Script.getExecutableAbsolutePath("grep");
56-
final String awk_path = Script.getExecutableAbsolutePath("awk");
57-
final String sed_path = Script.getExecutableAbsolutePath("sed");
58-
if(!command.isWindows()) {
59-
//List all dhcp lease files inside guestVm
60-
commands.add(new String[]{virt_ls_path, sanitizedVmName, "/var/lib/dhclient/"});
61-
commands.add(new String[]{grep_path, ".*\\*.leases"});
62-
String leasesList = Script.executePipedCommands(commands, 0).second();
63-
if(leasesList != null) {
64-
String[] leasesFiles = leasesList.split("\n");
65-
for(String leaseFile : leasesFiles){
66-
//Read from each dhclient lease file inside guest Vm using virt-cat libguestfs utility
67-
commands = new ArrayList<>();
68-
commands.add(new String[]{virt_cat_path, sanitizedVmName, "/var/lib/dhclient/" + leaseFile});
69-
commands.add(new String[]{tail_path, "-16"});
70-
commands.add(new String[]{grep_path, "fixed-address"});
71-
commands.add(new String[]{awk_path, "{print $2}"});
72-
commands.add(new String[]{sed_path, "-e", "s/;//"});
73-
String ipAddr = Script.executePipedCommands(commands, 0).second();
74-
// Check if the IP belongs to the network
75-
if((ipAddr != null) && NetUtils.isIpWithInCidrRange(ipAddr, networkCidr)) {
76-
ip = ipAddr;
77-
break;
96+
commands.add(new String[]{virsh_path, "domifaddr", sanitizedVmName, "--source", "agent"});
97+
Pair<Integer,String> response = executePipedCommands(commands, 0);
98+
if (response != null) {
99+
String output = response.second();
100+
String[] lines = output.split("\n");
101+
for (String line : lines) {
102+
if (line.contains("ipv4")) {
103+
String[] parts = line.split(" ");
104+
String[] ipParts = parts[parts.length-1].split("/");
105+
if (ipParts.length > 1) {
106+
if (NetUtils.isIpWithInCidrRange(ipParts[0], networkCidr)) {
107+
ip = ipParts[0];
108+
break;
109+
}
78110
}
79-
s_logger.debug("GetVmIp: "+ vmName + " Ip: "+ipAddr+" does not belong to network "+networkCidr);
80111
}
81112
}
82113
} else {
83-
// 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
84-
commands = new ArrayList<>();
85-
commands.add(new String[]{virt_win_reg_path, "--unsafe-printable-strings", sanitizedVmName, "HKEY_LOCAL_MACHINE\\SYSTEM\\ControlSet001\\Services\\Tcpip\\Parameters\\Interfaces"});
86-
commands.add(new String[]{grep_path, "DhcpIPAddress"});
87-
commands.add(new String[]{awk_path, "-F", ":", "{print $2}"});
88-
commands.add(new String[]{sed_path, "-e", "s/^\"//", "-e", "s/\"$//"});
89-
String ipList = Script.executePipedCommands(commands, 0).second();
90-
if(ipList != null) {
91-
s_logger.debug("GetVmIp: "+ vmName + "Ips: "+ipList);
92-
String[] ips = ipList.split("\n");
93-
for (String ipAddr : ips){
94-
// Check if the IP belongs to the network
95-
if((ipAddr != null) && NetUtils.isIpWithInCidrRange(ipAddr, networkCidr)){
96-
ip = ipAddr;
97-
break;
98-
}
99-
s_logger.debug("GetVmIp: "+ vmName + " Ip: "+ipAddr+" does not belong to network "+networkCidr);
114+
s_logger.error("ipFromDomIf: Command execution failed for VM: " + sanitizedVmName);
115+
}
116+
return ip;
117+
}
118+
119+
private String ipFromDhcpLeaseFile(String sanitizedVmName, String networkCidr) {
120+
String ip = null;
121+
List<String[]> commands = new ArrayList<>();
122+
commands.add(new String[]{virt_ls_path, sanitizedVmName, "/var/lib/dhclient/"});
123+
commands.add(new String[]{grep_path, ".*\\*.leases"});
124+
Pair<Integer,String> response = executePipedCommands(commands, 0);
125+
126+
if(response != null && response.second() != null) {
127+
String leasesList = response.second();
128+
String[] leasesFiles = leasesList.split("\n");
129+
for(String leaseFile : leasesFiles){
130+
commands = new ArrayList<>();
131+
commands.add(new String[]{virt_cat_path, sanitizedVmName, "/var/lib/dhclient/" + leaseFile});
132+
commands.add(new String[]{tail_path, "-16"});
133+
commands.add(new String[]{grep_path, "fixed-address"});
134+
commands.add(new String[]{awk_path, "{print $2}"});
135+
commands.add(new String[]{sed_path, "-e", "s/;//"});
136+
String ipAddr = executePipedCommands(commands, 0).second();
137+
if((ipAddr != null) && NetUtils.isIpWithInCidrRange(ipAddr, networkCidr)) {
138+
ip = ipAddr;
139+
break;
100140
}
141+
s_logger.debug("GetVmIp: "+ sanitizedVmName + " Ip: "+ipAddr+" does not belong to network "+networkCidr);
101142
}
143+
} else {
144+
s_logger.error("ipFromDhcpLeaseFile: Command execution failed for VM: " + sanitizedVmName);
102145
}
103-
if(ip != null){
104-
result = true;
105-
s_logger.debug("GetVmIp: "+ vmName + " Found Ip: "+ip);
146+
return ip;
147+
}
148+
149+
private String ipFromWindowsRegistry(String sanitizedVmName, String networkCidr) {
150+
String ip = null;
151+
List<String[]> commands = new ArrayList<>();
152+
commands.add(new String[]{virt_win_reg_path, "--unsafe-printable-strings", sanitizedVmName, "HKEY_LOCAL_MACHINE\\SYSTEM\\ControlSet001\\Services\\Tcpip\\Parameters\\Interfaces"});
153+
commands.add(new String[]{grep_path, "DhcpIPAddress"});
154+
commands.add(new String[]{awk_path, "-F", ":", "{print $2}"});
155+
commands.add(new String[]{sed_path, "-e", "s/^\"//", "-e", "s/\"$//"});
156+
Pair<Integer,String> pair = executePipedCommands(commands, 0);
157+
if(pair != null && pair.second() != null) {
158+
String ipList = pair.second();
159+
ipList = ipList.replaceAll("\"", "");
160+
s_logger.debug("GetVmIp: "+ sanitizedVmName + "Ips: "+ipList);
161+
String[] ips = ipList.split("\n");
162+
for (String ipAddr : ips){
163+
if((ipAddr != null) && NetUtils.isIpWithInCidrRange(ipAddr, networkCidr)){
164+
ip = ipAddr;
165+
break;
166+
}
167+
s_logger.debug("GetVmIp: "+ sanitizedVmName + " Ip: "+ipAddr+" does not belong to network "+networkCidr);
168+
}
169+
} else {
170+
s_logger.error("ipFromWindowsRegistry: Command execution failed for VM: " + sanitizedVmName);
106171
}
107-
return new Answer(command, result, ip);
172+
return ip;
173+
}
174+
175+
static Pair<Integer, String> executePipedCommands(List<String[]> commands, long timeout) {
176+
return Script.executePipedCommands(commands, timeout);
108177
}
109178
}

0 commit comments

Comments
 (0)