Skip to content

Commit 7434d91

Browse files
authored
Merge pull request #1873 from Accelerite/dhcpOffloadFix
CLOUDSTACK-9709: Updated the vm ip fetch task to use the correct the …
2 parents 0fefc20 + e3ae08b commit 7434d91

4 files changed

Lines changed: 209 additions & 6 deletions

File tree

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
//
2+
// Licensed to the Apache Software Foundation (ASF) under one
3+
// or more contributor license agreements. See the NOTICE file
4+
// distributed with this work for additional information
5+
// regarding copyright ownership. The ASF licenses this file
6+
// to you under the Apache License, Version 2.0 (the
7+
// "License"); you may not use this file except in compliance
8+
// with the License. You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing,
13+
// software distributed under the License is distributed on an
14+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
// KIND, either express or implied. See the License for the
16+
// specific language governing permissions and limitations
17+
// under the License.
18+
//
19+
20+
package com.cloud.hypervisor.kvm.resource.wrapper;
21+
22+
import com.cloud.agent.api.Answer;
23+
import com.cloud.agent.api.GetVmIpAddressCommand;
24+
import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource;
25+
import com.cloud.resource.CommandWrapper;
26+
import com.cloud.resource.ResourceWrapper;
27+
import com.cloud.utils.net.NetUtils;
28+
import com.cloud.utils.script.Script;
29+
import org.apache.log4j.Logger;
30+
31+
@ResourceWrapper(handles = GetVmIpAddressCommand.class)
32+
public final class LibvirtGetVmIpAddressCommandWrapper extends CommandWrapper<GetVmIpAddressCommand, Answer, LibvirtComputingResource> {
33+
34+
private static final Logger s_logger = Logger.getLogger(LibvirtGetVmIpAddressCommandWrapper.class);
35+
36+
@Override
37+
public Answer execute(final GetVmIpAddressCommand command, final LibvirtComputingResource libvirtComputingResource) {
38+
String ip = null;
39+
boolean result = false;
40+
String networkCidr = command.getVmNetworkCidr();
41+
if(!command.isWindows()) {
42+
//List all dhcp lease files inside guestVm
43+
String leasesList = Script.runSimpleBashScript(new StringBuilder().append("virt-ls ").append(command.getVmName())
44+
.append(" /var/lib/dhclient/ | grep .*\\*.leases").toString());
45+
if(leasesList != null) {
46+
String[] leasesFiles = leasesList.split("\n");
47+
for(String leaseFile : leasesFiles){
48+
//Read from each dhclient lease file inside guest Vm using virt-cat libguestfs ulitiy
49+
String ipAddr = Script.runSimpleBashScript(new StringBuilder().append("virt-cat ").append(command.getVmName())
50+
.append(" /var/lib/dhclient/" + leaseFile + " | tail -16 | grep 'fixed-address' | awk '{print $2}' | sed -e 's/;//'").toString());
51+
// Check if the IP belongs to the network
52+
if((ipAddr != null) && NetUtils.isIpWithtInCidrRange(ipAddr, networkCidr)){
53+
ip = ipAddr;
54+
break;
55+
}
56+
s_logger.debug("GetVmIp: "+command.getVmName()+ " Ip: "+ipAddr+" does not belong to network "+networkCidr);
57+
}
58+
}
59+
} else {
60+
// 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
61+
String ipList = Script.runSimpleBashScript(new StringBuilder().append("virt-win-reg --unsafe-printable-strings ").append(command.getVmName())
62+
.append(" 'HKEY_LOCAL_MACHINE\\SYSTEM\\ControlSet001\\Services\\Tcpip\\Parameters\\Interfaces' | grep DhcpIPAddress | awk -F : '{print $2}' | sed -e 's/^\"//' -e 's/\"$//'").toString());
63+
if(ipList != null) {
64+
s_logger.debug("GetVmIp: "+command.getVmName()+ "Ips: "+ipList);
65+
String[] ips = ipList.split("\n");
66+
for (String ipAddr : ips){
67+
// Check if the IP belongs to the network
68+
if((ipAddr != null) && NetUtils.isIpWithtInCidrRange(ipAddr, networkCidr)){
69+
ip = ipAddr;
70+
break;
71+
}
72+
s_logger.debug("GetVmIp: "+command.getVmName()+ " Ip: "+ipAddr+" does not belong to network "+networkCidr);
73+
}
74+
}
75+
}
76+
if(ip != null){
77+
result = true;
78+
s_logger.debug("GetVmIp: "+command.getVmName()+ " Found Ip: "+ip);
79+
}
80+
return new Answer(command, result, ip);
81+
}
82+
}

plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,9 @@
290290
import com.cloud.vm.VirtualMachine.PowerState;
291291
import com.cloud.vm.VirtualMachineName;
292292
import com.cloud.vm.VmDetailConstants;
293+
import com.vmware.vim25.GuestInfo;
294+
import com.vmware.vim25.VirtualMachineToolsStatus;
295+
import com.cloud.agent.api.GetVmIpAddressCommand;
293296

294297
public class VmwareResource implements StoragePoolResource, ServerResource, VmwareHostService, VirtualRouterDeployer {
295298
private static final Logger s_logger = Logger.getLogger(VmwareResource.class);
@@ -490,6 +493,8 @@ public Answer executeRequest(Command cmd) {
490493
return execute((ScaleVmCommand)cmd);
491494
} else if (clz == PvlanSetupCommand.class) {
492495
return execute((PvlanSetupCommand)cmd);
496+
} else if (clz == GetVmIpAddressCommand.class) {
497+
return execute((GetVmIpAddressCommand)cmd);
493498
} else if (clz == UnregisterNicCommand.class) {
494499
answer = execute((UnregisterNicCommand)cmd);
495500
} else {
@@ -3285,11 +3290,17 @@ protected Answer execute(RebootCommand cmd) {
32853290
s_logger.info("Executing resource RebootCommand: " + _gson.toJson(cmd));
32863291
}
32873292

3293+
boolean toolsInstallerMounted = false;
3294+
VirtualMachineMO vmMo = null;
32883295
VmwareContext context = getServiceContext();
32893296
VmwareHypervisorHost hyperHost = getHyperHost(context);
32903297
try {
3291-
VirtualMachineMO vmMo = hyperHost.findVmOnHyperHost(cmd.getVmName());
3298+
vmMo = hyperHost.findVmOnHyperHost(cmd.getVmName());
32923299
if (vmMo != null) {
3300+
if (vmMo.isToolsInstallerMounted()) {
3301+
toolsInstallerMounted = true;
3302+
s_logger.trace("Detected mounted vmware tools installer for :[" + cmd.getVmName() + "]");
3303+
}
32933304
try {
32943305
vmMo.rebootGuest();
32953306
return new RebootAnswer(cmd, "reboot succeeded", true);
@@ -3321,6 +3332,15 @@ protected Answer execute(RebootCommand cmd) {
33213332
String msg = "RebootCommand failed due to " + VmwareHelper.getExceptionMessage(e);
33223333
s_logger.error(msg);
33233334
return new RebootAnswer(cmd, msg, false);
3335+
} finally {
3336+
if (toolsInstallerMounted) {
3337+
try {
3338+
vmMo.mountToolsInstaller();
3339+
s_logger.debug("Successfully re-mounted vmware tools installer for :[" + cmd.getVmName() + "]");
3340+
} catch (Exception e) {
3341+
s_logger.warn("Unabled to re-mount vmware tools installer for :[" + cmd.getVmName() + "]");
3342+
}
3343+
}
33243344
}
33253345
}
33263346

@@ -4430,6 +4450,59 @@ protected Answer execute(ModifySshKeysCommand cmd) {
44304450
}
44314451

44324452

4453+
protected Answer execute(GetVmIpAddressCommand cmd) {
4454+
if (s_logger.isTraceEnabled()) {
4455+
s_logger.trace("Executing resource command GetVmIpAddressCommand: " + _gson.toJson(cmd));
4456+
}
4457+
4458+
String details = "Unable to find IP Address of VM. ";
4459+
String vmName = cmd.getVmName();
4460+
boolean result = false;
4461+
String ip = null;
4462+
Answer answer = null;
4463+
4464+
VmwareContext context = getServiceContext();
4465+
VmwareHypervisorHost hyperHost = getHyperHost(context);
4466+
4467+
if (vmName == null || vmName.isEmpty()) {
4468+
details += "Name of instance provided is NULL or empty.";
4469+
return new Answer(cmd, result, details);
4470+
}
4471+
4472+
try {
4473+
VirtualMachineMO vmMo = hyperHost.findVmOnHyperHost(vmName);
4474+
if (vmMo != null) {
4475+
GuestInfo guestInfo = vmMo.getGuestInfo();
4476+
VirtualMachineToolsStatus toolsStatus = guestInfo.getToolsStatus();
4477+
if (toolsStatus == VirtualMachineToolsStatus.TOOLS_NOT_INSTALLED) {
4478+
details += "Vmware tools not installed.";
4479+
} else {
4480+
ip = guestInfo.getIpAddress();
4481+
if (ip != null) {
4482+
result = true;
4483+
}
4484+
details = ip;
4485+
}
4486+
} else {
4487+
details += "VM " + vmName + " no longer exists on vSphere host: " + hyperHost.getHyperHostName();
4488+
s_logger.info(details);
4489+
}
4490+
} catch (Throwable e) {
4491+
if (e instanceof RemoteException) {
4492+
s_logger.warn("Encounter remote exception to vCenter, invalidate VMware session context");
4493+
invalidateServiceContext();
4494+
}
4495+
details += "Encountered exception : " + VmwareHelper.getExceptionMessage(e);
4496+
s_logger.error(details);
4497+
}
4498+
4499+
answer = new Answer(cmd, result, details);
4500+
if (s_logger.isTraceEnabled()) {
4501+
s_logger.trace("Returning GetVmIpAddressAnswer: " + _gson.toJson(answer));
4502+
}
4503+
return answer;
4504+
}
4505+
44334506
@Override
44344507
public PrimaryStorageDownloadAnswer execute(PrimaryStorageDownloadCommand cmd) {
44354508
if (s_logger.isInfoEnabled()) {

server/src/com/cloud/vm/UserVmManagerImpl.java

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
477477
protected IpAddressManager _ipAddrMgr;
478478

479479
protected ScheduledExecutorService _executor = null;
480+
protected ScheduledExecutorService _vmIpFetchExecutor = null;
480481
protected int _expungeInterval;
481482
protected int _expungeDelay;
482483
protected boolean _dailyOrHourly = false;
@@ -514,6 +515,9 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
514515
static final ConfigKey<Integer> VmIpFetchThreadPoolMax = new ConfigKey<Integer>("Advanced", Integer.class, "externaldhcp.vmipFetch.threadPool.max", "10",
515516
"number of threads for fetching vms ip address", true);
516517

518+
static final ConfigKey<Integer> VmIpFetchTaskWorkers = new ConfigKey<Integer>("Advanced", Integer.class, "externaldhcp.vmipfetchtask.workers", "10",
519+
"number of worker threads for vm ip fetch task ", true);
520+
517521

518522
@Override
519523
public UserVmVO getVirtualMachine(long vmId) {
@@ -1947,6 +1951,11 @@ public boolean configure(String name, Map<String, Object> params) throws Configu
19471951

19481952
_executor = Executors.newScheduledThreadPool(wrks, new NamedThreadFactory("UserVm-Scavenger"));
19491953

1954+
String vmIpWorkers = configs.get(VmIpFetchTaskWorkers.value());
1955+
int vmipwrks = NumbersUtil.parseInt(vmIpWorkers, 10);
1956+
1957+
_vmIpFetchExecutor = Executors.newScheduledThreadPool(vmipwrks, new NamedThreadFactory("UserVm-ipfetch"));
1958+
19501959
String aggregationRange = configs.get("usage.stats.job.aggregation.range");
19511960
int _usageAggregationRange = NumbersUtil.parseInt(aggregationRange, 1440);
19521961
int HOURLY_TIME = 60;
@@ -1966,7 +1975,9 @@ public boolean configure(String name, Map<String, Object> params) throws Configu
19661975
String value = _configDao.getValue(Config.SetVmInternalNameUsingDisplayName.key());
19671976
_instanceNameFlag = (value == null) ? false : Boolean.parseBoolean(value);
19681977

1969-
_scaleRetry = NumbersUtil.parseInt(configs.get(Config.ScaleRetry.key()), 2);
1978+
_scaleRetry = NumbersUtil.parseInt(configs.get(Config.ScaleRetry.key()), 2);
1979+
1980+
_vmIpFetchThreadExecutor = Executors.newFixedThreadPool(VmIpFetchThreadPoolMax.value(), new NamedThreadFactory("vmIpFetchThread"));
19701981

19711982
s_logger.info("User VM Manager is configured.");
19721983

@@ -1981,7 +1992,7 @@ public String getName() {
19811992
@Override
19821993
public boolean start() {
19831994
_executor.scheduleWithFixedDelay(new ExpungeTask(), _expungeInterval, _expungeInterval, TimeUnit.SECONDS);
1984-
_executor.scheduleWithFixedDelay(new VmIpFetchTask(), VmIpFetchWaitInterval.value(), VmIpFetchWaitInterval.value(), TimeUnit.SECONDS);
1995+
_vmIpFetchExecutor.scheduleWithFixedDelay(new VmIpFetchTask(), VmIpFetchWaitInterval.value(), VmIpFetchWaitInterval.value(), TimeUnit.SECONDS);
19851996
loadVmDetailsInMapForExternalDhcpIp();
19861997
return true;
19871998
}
@@ -2015,6 +2026,7 @@ private void loadVmDetailsInMapForExternalDhcpIp() {
20152026
@Override
20162027
public boolean stop() {
20172028
_executor.shutdown();
2029+
_vmIpFetchExecutor.shutdown();
20182030
return true;
20192031
}
20202032

@@ -2599,7 +2611,21 @@ public UserVm rebootVirtualMachine(RebootVMCmd cmd) throws InsufficientCapacityE
25992611
throw new InvalidParameterValueException("Unable to find service offering: " + serviceOfferingId + " corresponding to the vm");
26002612
}
26012613

2602-
return rebootVirtualMachine(CallContext.current().getCallingUserId(), vmId);
2614+
UserVm userVm = rebootVirtualMachine(CallContext.current().getCallingUserId(), vmId);
2615+
if (userVm != null ) {
2616+
// update the vmIdCountMap if the vm is in advanced shared network with out services
2617+
final List<NicVO> nics = _nicDao.listByVmId(vmId);
2618+
for (NicVO nic : nics) {
2619+
Network network = _networkModel.getNetwork(nic.getNetworkId());
2620+
if (_networkModel.isSharedNetworkWithoutServices(network.getId())) {
2621+
s_logger.debug("Adding vm " +vmId +" nic id "+ nic.getId() +" into vmIdCountMap as part of vm " +
2622+
"reboot for vm ip fetch ");
2623+
vmIdCountMap.put(nic.getId(), new VmAndCountDetails(nic.getInstanceId(), VmIpFetchTrialMax.value()));
2624+
}
2625+
}
2626+
return userVm;
2627+
}
2628+
return null;
26032629
}
26042630

26052631
@Override
@@ -3821,7 +3847,7 @@ public boolean finalizeCommandsOnStart(Commands cmds, VirtualMachineProfile prof
38213847
}
38223848

38233849
@Override
3824-
public boolean finalizeStart(VirtualMachineProfile profile, long hostId, Commands cmds, ReservationContext context) {
3850+
public boolean finalizeStart(VirtualMachineProfile profile, long hostId, Commands cmds, ReservationContext context) {
38253851
UserVmVO vm = _vmDao.findById(profile.getId());
38263852

38273853
Answer[] answersToCmds = cmds.getAnswers();
@@ -3909,6 +3935,21 @@ public boolean finalizeStart(VirtualMachineProfile profile, long hostId, Command
39093935
}
39103936
}
39113937

3938+
final VirtualMachineProfile vmProfile = profile;
3939+
Transaction.execute(new TransactionCallbackNoReturn() {
3940+
@Override
3941+
public void doInTransactionWithoutResult(TransactionStatus status) {
3942+
final UserVmVO vm = _vmDao.findById(vmProfile.getId());
3943+
final List<NicVO> nics = _nicDao.listByVmId(vm.getId());
3944+
for (NicVO nic : nics) {
3945+
Network network = _networkModel.getNetwork(nic.getNetworkId());
3946+
if (_networkModel.isSharedNetworkWithoutServices(network.getId())) {
3947+
vmIdCountMap.put(nic.getId(), new VmAndCountDetails(nic.getInstanceId(), VmIpFetchTrialMax.value()));
3948+
}
3949+
}
3950+
}
3951+
});
3952+
39123953
return true;
39133954
}
39143955

@@ -5848,7 +5889,7 @@ public String getConfigComponentName() {
58485889

58495890
@Override
58505891
public ConfigKey<?>[] getConfigKeys() {
5851-
return new ConfigKey<?>[] {EnableDynamicallyScaleVm, AllowUserExpungeRecoverVm, VmIpFetchWaitInterval, VmIpFetchTrialMax, VmIpFetchThreadPoolMax};
5892+
return new ConfigKey<?>[] {EnableDynamicallyScaleVm, AllowUserExpungeRecoverVm, VmIpFetchWaitInterval, VmIpFetchTrialMax, VmIpFetchThreadPoolMax, VmIpFetchTaskWorkers};
58525893
}
58535894

58545895
@Override

vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -751,6 +751,13 @@ public VirtualMachineConfigInfo getConfigInfo() throws Exception {
751751
return (VirtualMachineConfigInfo)_context.getVimClient().getDynamicProperty(_mor, "config");
752752
}
753753

754+
public boolean isToolsInstallerMounted() throws Exception {
755+
return _context.getVimClient().getDynamicProperty(_mor, "runtime.toolsInstallerMounted");
756+
}
757+
public GuestInfo getGuestInfo() throws Exception {
758+
return (GuestInfo)_context.getVimClient().getDynamicProperty(_mor, "guest");
759+
}
760+
754761
public VirtualMachineConfigSummary getConfigSummary() throws Exception {
755762
return (VirtualMachineConfigSummary)_context.getVimClient().getDynamicProperty(_mor, "summary.config");
756763
}

0 commit comments

Comments
 (0)