Merge pull request #1873 from Accelerite/dhcpOffloadFix

CLOUDSTACK-9709: Updated the vm ip fetch task to use the correct the …
This commit is contained in:
Rajani Karuturi 2017-05-17 10:43:51 +05:30 committed by GitHub
commit 7434d91614
4 changed files with 209 additions and 6 deletions

View File

@ -0,0 +1,82 @@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
package com.cloud.hypervisor.kvm.resource.wrapper;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.GetVmIpAddressCommand;
import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource;
import com.cloud.resource.CommandWrapper;
import com.cloud.resource.ResourceWrapper;
import com.cloud.utils.net.NetUtils;
import com.cloud.utils.script.Script;
import org.apache.log4j.Logger;
@ResourceWrapper(handles = GetVmIpAddressCommand.class)
public final class LibvirtGetVmIpAddressCommandWrapper extends CommandWrapper<GetVmIpAddressCommand, Answer, LibvirtComputingResource> {
private static final Logger s_logger = Logger.getLogger(LibvirtGetVmIpAddressCommandWrapper.class);
@Override
public Answer execute(final GetVmIpAddressCommand command, final LibvirtComputingResource libvirtComputingResource) {
String ip = null;
boolean result = false;
String networkCidr = command.getVmNetworkCidr();
if(!command.isWindows()) {
//List all dhcp lease files inside guestVm
String leasesList = Script.runSimpleBashScript(new StringBuilder().append("virt-ls ").append(command.getVmName())
.append(" /var/lib/dhclient/ | grep .*\\*.leases").toString());
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 ulitiy
String ipAddr = Script.runSimpleBashScript(new StringBuilder().append("virt-cat ").append(command.getVmName())
.append(" /var/lib/dhclient/" + leaseFile + " | tail -16 | grep 'fixed-address' | awk '{print $2}' | sed -e 's/;//'").toString());
// Check if the IP belongs to the network
if((ipAddr != null) && NetUtils.isIpWithtInCidrRange(ipAddr, networkCidr)){
ip = ipAddr;
break;
}
s_logger.debug("GetVmIp: "+command.getVmName()+ " 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
String ipList = Script.runSimpleBashScript(new StringBuilder().append("virt-win-reg --unsafe-printable-strings ").append(command.getVmName())
.append(" 'HKEY_LOCAL_MACHINE\\SYSTEM\\ControlSet001\\Services\\Tcpip\\Parameters\\Interfaces' | grep DhcpIPAddress | awk -F : '{print $2}' | sed -e 's/^\"//' -e 's/\"$//'").toString());
if(ipList != null) {
s_logger.debug("GetVmIp: "+command.getVmName()+ "Ips: "+ipList);
String[] ips = ipList.split("\n");
for (String ipAddr : ips){
// Check if the IP belongs to the network
if((ipAddr != null) && NetUtils.isIpWithtInCidrRange(ipAddr, networkCidr)){
ip = ipAddr;
break;
}
s_logger.debug("GetVmIp: "+command.getVmName()+ " Ip: "+ipAddr+" does not belong to network "+networkCidr);
}
}
}
if(ip != null){
result = true;
s_logger.debug("GetVmIp: "+command.getVmName()+ " Found Ip: "+ip);
}
return new Answer(command, result, ip);
}
}

View File

@ -290,6 +290,9 @@ import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachine.PowerState;
import com.cloud.vm.VirtualMachineName;
import com.cloud.vm.VmDetailConstants;
import com.vmware.vim25.GuestInfo;
import com.vmware.vim25.VirtualMachineToolsStatus;
import com.cloud.agent.api.GetVmIpAddressCommand;
public class VmwareResource implements StoragePoolResource, ServerResource, VmwareHostService, VirtualRouterDeployer {
private static final Logger s_logger = Logger.getLogger(VmwareResource.class);
@ -490,6 +493,8 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
return execute((ScaleVmCommand)cmd);
} else if (clz == PvlanSetupCommand.class) {
return execute((PvlanSetupCommand)cmd);
} else if (clz == GetVmIpAddressCommand.class) {
return execute((GetVmIpAddressCommand)cmd);
} else if (clz == UnregisterNicCommand.class) {
answer = execute((UnregisterNicCommand)cmd);
} else {
@ -3285,11 +3290,17 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
s_logger.info("Executing resource RebootCommand: " + _gson.toJson(cmd));
}
boolean toolsInstallerMounted = false;
VirtualMachineMO vmMo = null;
VmwareContext context = getServiceContext();
VmwareHypervisorHost hyperHost = getHyperHost(context);
try {
VirtualMachineMO vmMo = hyperHost.findVmOnHyperHost(cmd.getVmName());
vmMo = hyperHost.findVmOnHyperHost(cmd.getVmName());
if (vmMo != null) {
if (vmMo.isToolsInstallerMounted()) {
toolsInstallerMounted = true;
s_logger.trace("Detected mounted vmware tools installer for :[" + cmd.getVmName() + "]");
}
try {
vmMo.rebootGuest();
return new RebootAnswer(cmd, "reboot succeeded", true);
@ -3321,6 +3332,15 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
String msg = "RebootCommand failed due to " + VmwareHelper.getExceptionMessage(e);
s_logger.error(msg);
return new RebootAnswer(cmd, msg, false);
} finally {
if (toolsInstallerMounted) {
try {
vmMo.mountToolsInstaller();
s_logger.debug("Successfully re-mounted vmware tools installer for :[" + cmd.getVmName() + "]");
} catch (Exception e) {
s_logger.warn("Unabled to re-mount vmware tools installer for :[" + cmd.getVmName() + "]");
}
}
}
}
@ -4430,6 +4450,59 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
}
protected Answer execute(GetVmIpAddressCommand cmd) {
if (s_logger.isTraceEnabled()) {
s_logger.trace("Executing resource command GetVmIpAddressCommand: " + _gson.toJson(cmd));
}
String details = "Unable to find IP Address of VM. ";
String vmName = cmd.getVmName();
boolean result = false;
String ip = null;
Answer answer = null;
VmwareContext context = getServiceContext();
VmwareHypervisorHost hyperHost = getHyperHost(context);
if (vmName == null || vmName.isEmpty()) {
details += "Name of instance provided is NULL or empty.";
return new Answer(cmd, result, details);
}
try {
VirtualMachineMO vmMo = hyperHost.findVmOnHyperHost(vmName);
if (vmMo != null) {
GuestInfo guestInfo = vmMo.getGuestInfo();
VirtualMachineToolsStatus toolsStatus = guestInfo.getToolsStatus();
if (toolsStatus == VirtualMachineToolsStatus.TOOLS_NOT_INSTALLED) {
details += "Vmware tools not installed.";
} else {
ip = guestInfo.getIpAddress();
if (ip != null) {
result = true;
}
details = ip;
}
} else {
details += "VM " + vmName + " no longer exists on vSphere host: " + hyperHost.getHyperHostName();
s_logger.info(details);
}
} catch (Throwable e) {
if (e instanceof RemoteException) {
s_logger.warn("Encounter remote exception to vCenter, invalidate VMware session context");
invalidateServiceContext();
}
details += "Encountered exception : " + VmwareHelper.getExceptionMessage(e);
s_logger.error(details);
}
answer = new Answer(cmd, result, details);
if (s_logger.isTraceEnabled()) {
s_logger.trace("Returning GetVmIpAddressAnswer: " + _gson.toJson(answer));
}
return answer;
}
@Override
public PrimaryStorageDownloadAnswer execute(PrimaryStorageDownloadCommand cmd) {
if (s_logger.isInfoEnabled()) {

View File

@ -477,6 +477,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
protected IpAddressManager _ipAddrMgr;
protected ScheduledExecutorService _executor = null;
protected ScheduledExecutorService _vmIpFetchExecutor = null;
protected int _expungeInterval;
protected int _expungeDelay;
protected boolean _dailyOrHourly = false;
@ -514,6 +515,9 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
static final ConfigKey<Integer> VmIpFetchThreadPoolMax = new ConfigKey<Integer>("Advanced", Integer.class, "externaldhcp.vmipFetch.threadPool.max", "10",
"number of threads for fetching vms ip address", true);
static final ConfigKey<Integer> VmIpFetchTaskWorkers = new ConfigKey<Integer>("Advanced", Integer.class, "externaldhcp.vmipfetchtask.workers", "10",
"number of worker threads for vm ip fetch task ", true);
@Override
public UserVmVO getVirtualMachine(long vmId) {
@ -1947,6 +1951,11 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
_executor = Executors.newScheduledThreadPool(wrks, new NamedThreadFactory("UserVm-Scavenger"));
String vmIpWorkers = configs.get(VmIpFetchTaskWorkers.value());
int vmipwrks = NumbersUtil.parseInt(vmIpWorkers, 10);
_vmIpFetchExecutor = Executors.newScheduledThreadPool(vmipwrks, new NamedThreadFactory("UserVm-ipfetch"));
String aggregationRange = configs.get("usage.stats.job.aggregation.range");
int _usageAggregationRange = NumbersUtil.parseInt(aggregationRange, 1440);
int HOURLY_TIME = 60;
@ -1966,7 +1975,9 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
String value = _configDao.getValue(Config.SetVmInternalNameUsingDisplayName.key());
_instanceNameFlag = (value == null) ? false : Boolean.parseBoolean(value);
_scaleRetry = NumbersUtil.parseInt(configs.get(Config.ScaleRetry.key()), 2);
_scaleRetry = NumbersUtil.parseInt(configs.get(Config.ScaleRetry.key()), 2);
_vmIpFetchThreadExecutor = Executors.newFixedThreadPool(VmIpFetchThreadPoolMax.value(), new NamedThreadFactory("vmIpFetchThread"));
s_logger.info("User VM Manager is configured.");
@ -1981,7 +1992,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
@Override
public boolean start() {
_executor.scheduleWithFixedDelay(new ExpungeTask(), _expungeInterval, _expungeInterval, TimeUnit.SECONDS);
_executor.scheduleWithFixedDelay(new VmIpFetchTask(), VmIpFetchWaitInterval.value(), VmIpFetchWaitInterval.value(), TimeUnit.SECONDS);
_vmIpFetchExecutor.scheduleWithFixedDelay(new VmIpFetchTask(), VmIpFetchWaitInterval.value(), VmIpFetchWaitInterval.value(), TimeUnit.SECONDS);
loadVmDetailsInMapForExternalDhcpIp();
return true;
}
@ -2015,6 +2026,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
@Override
public boolean stop() {
_executor.shutdown();
_vmIpFetchExecutor.shutdown();
return true;
}
@ -2599,7 +2611,21 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
throw new InvalidParameterValueException("Unable to find service offering: " + serviceOfferingId + " corresponding to the vm");
}
return rebootVirtualMachine(CallContext.current().getCallingUserId(), vmId);
UserVm userVm = rebootVirtualMachine(CallContext.current().getCallingUserId(), vmId);
if (userVm != null ) {
// update the vmIdCountMap if the vm is in advanced shared network with out services
final List<NicVO> nics = _nicDao.listByVmId(vmId);
for (NicVO nic : nics) {
Network network = _networkModel.getNetwork(nic.getNetworkId());
if (_networkModel.isSharedNetworkWithoutServices(network.getId())) {
s_logger.debug("Adding vm " +vmId +" nic id "+ nic.getId() +" into vmIdCountMap as part of vm " +
"reboot for vm ip fetch ");
vmIdCountMap.put(nic.getId(), new VmAndCountDetails(nic.getInstanceId(), VmIpFetchTrialMax.value()));
}
}
return userVm;
}
return null;
}
@Override
@ -3821,7 +3847,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
}
@Override
public boolean finalizeStart(VirtualMachineProfile profile, long hostId, Commands cmds, ReservationContext context) {
public boolean finalizeStart(VirtualMachineProfile profile, long hostId, Commands cmds, ReservationContext context) {
UserVmVO vm = _vmDao.findById(profile.getId());
Answer[] answersToCmds = cmds.getAnswers();
@ -3909,6 +3935,21 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
}
}
final VirtualMachineProfile vmProfile = profile;
Transaction.execute(new TransactionCallbackNoReturn() {
@Override
public void doInTransactionWithoutResult(TransactionStatus status) {
final UserVmVO vm = _vmDao.findById(vmProfile.getId());
final List<NicVO> nics = _nicDao.listByVmId(vm.getId());
for (NicVO nic : nics) {
Network network = _networkModel.getNetwork(nic.getNetworkId());
if (_networkModel.isSharedNetworkWithoutServices(network.getId())) {
vmIdCountMap.put(nic.getId(), new VmAndCountDetails(nic.getInstanceId(), VmIpFetchTrialMax.value()));
}
}
}
});
return true;
}
@ -5848,7 +5889,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
@Override
public ConfigKey<?>[] getConfigKeys() {
return new ConfigKey<?>[] {EnableDynamicallyScaleVm, AllowUserExpungeRecoverVm, VmIpFetchWaitInterval, VmIpFetchTrialMax, VmIpFetchThreadPoolMax};
return new ConfigKey<?>[] {EnableDynamicallyScaleVm, AllowUserExpungeRecoverVm, VmIpFetchWaitInterval, VmIpFetchTrialMax, VmIpFetchThreadPoolMax, VmIpFetchTaskWorkers};
}
@Override

View File

@ -751,6 +751,13 @@ public class VirtualMachineMO extends BaseMO {
return (VirtualMachineConfigInfo)_context.getVimClient().getDynamicProperty(_mor, "config");
}
public boolean isToolsInstallerMounted() throws Exception {
return _context.getVimClient().getDynamicProperty(_mor, "runtime.toolsInstallerMounted");
}
public GuestInfo getGuestInfo() throws Exception {
return (GuestInfo)_context.getVimClient().getDynamicProperty(_mor, "guest");
}
public VirtualMachineConfigSummary getConfigSummary() throws Exception {
return (VirtualMachineConfigSummary)_context.getVimClient().getDynamicProperty(_mor, "summary.config");
}