blob: 9de6ba8ab4f7ab53c7578324fc3a5ba1ec4f4d21 [file] [log] [blame]
// 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;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory;
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.framework.config.Configurable;
import org.apache.cloudstack.hypervisor.xenserver.XenserverConfigs;
import org.apache.cloudstack.resourcedetail.dao.GuestOsDetailsDao;
import org.apache.cloudstack.storage.command.CopyCommand;
import org.apache.cloudstack.storage.command.DettachCommand;
import org.apache.cloudstack.storage.command.StorageSubSystemCommand;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import com.cloud.agent.api.Command;
import com.cloud.agent.api.to.DataObjectType;
import com.cloud.agent.api.to.DataStoreTO;
import com.cloud.agent.api.to.DataTO;
import com.cloud.agent.api.to.DiskTO;
import com.cloud.agent.api.to.NfsTO;
import com.cloud.agent.api.to.VirtualMachineTO;
import com.cloud.host.HostVO;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.storage.GuestOSHypervisorVO;
import com.cloud.storage.GuestOSVO;
import com.cloud.storage.VolumeVO;
import com.cloud.storage.dao.GuestOSDao;
import com.cloud.storage.dao.GuestOSHypervisorDao;
import com.cloud.storage.dao.VolumeDao;
import com.cloud.template.VirtualMachineTemplate.BootloaderType;
import com.cloud.utils.Pair;
import com.cloud.vm.UserVmVO;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachineProfile;
import com.cloud.vm.dao.UserVmDao;
public class XenServerGuru extends HypervisorGuruBase implements HypervisorGuru, Configurable {
private Logger logger = Logger.getLogger(getClass());
@Inject
private GuestOSDao guestOsDao;
@Inject
private GuestOSHypervisorDao guestOsHypervisorDao;
@Inject
private VolumeDao volumeDao;
@Inject
private PrimaryDataStoreDao storagePoolDao;
@Inject
private VolumeDataFactory volFactory;
@Inject
private UserVmDao userVmDao;
@Inject
private GuestOsDetailsDao guestOsDetailsDao;
private static final ConfigKey<Integer> MaxNumberOfVCPUSPerVM = new ConfigKey<Integer>("Advanced", Integer.class, "xen.vm.vcpu.max", "16",
"Maximum number of VCPUs that VM can get in XenServer.", true, ConfigKey.Scope.Cluster);
@Override
public HypervisorType getHypervisorType() {
return HypervisorType.XenServer;
}
@Override
public VirtualMachineTO implement(VirtualMachineProfile vm) {
BootloaderType bt = BootloaderType.PyGrub;
if (vm.getBootLoaderType() == BootloaderType.CD) {
bt = vm.getBootLoaderType();
}
VirtualMachineTO to = toVirtualMachineTO(vm);
UserVmVO userVmVO = userVmDao.findById(vm.getId());
if (userVmVO != null) {
HostVO host = hostDao.findById(userVmVO.getHostId());
if (host != null) {
to.setVcpuMaxLimit(MaxNumberOfVCPUSPerVM.valueIn(host.getClusterId()));
}
}
to.setBootloader(bt);
// Determine the VM's OS description
GuestOSVO guestOS = guestOsDao.findByIdIncludingRemoved(vm.getVirtualMachine().getGuestOSId());
Map<String, String> guestOsDetails = guestOsDetailsDao.listDetailsKeyPairs(vm.getVirtualMachine().getGuestOSId());
to.setGuestOsDetails(guestOsDetails);
to.setOs(guestOS.getDisplayName());
HostVO host = hostDao.findById(vm.getVirtualMachine().getHostId());
GuestOSHypervisorVO guestOsMapping = null;
if (host != null) {
guestOsMapping = guestOsHypervisorDao.findByOsIdAndHypervisor(guestOS.getId(), getHypervisorType().toString(), host.getHypervisorVersion());
}
if (guestOsMapping == null || host == null) {
to.setPlatformEmulator(null);
} else {
to.setPlatformEmulator(guestOsMapping.getGuestOsName());
}
return to;
}
@Override
public boolean trackVmHostChange() {
return true;
}
@Override
public List<Command> finalizeExpungeVolumes(VirtualMachine vm) {
List<Command> commands = new ArrayList<Command>();
List<VolumeVO> volumes = volumeDao.findByInstance(vm.getId());
// it's OK in this case to send a detach command to the host for a root volume as this
// will simply lead to the SR that supports the root volume being removed
if (volumes != null) {
for (VolumeVO volume : volumes) {
StoragePoolVO storagePool = storagePoolDao.findById(volume.getPoolId());
// storagePool should be null if we are expunging a volume that was never
// attached to a VM that was started (the "trick" for storagePool to be null
// is that none of the VMs this volume may have been attached to were ever started,
// so the volume was never assigned to a storage pool)
if (storagePool != null && storagePool.isManaged()) {
DataTO volTO = volFactory.getVolume(volume.getId()).getTO();
DiskTO disk = new DiskTO(volTO, volume.getDeviceId(), volume.getPath(), volume.getVolumeType());
DettachCommand cmd = new DettachCommand(disk, vm.getInstanceName());
cmd.setManaged(true);
cmd.setStorageHost(storagePool.getHostAddress());
cmd.setStoragePort(storagePool.getPort());
cmd.set_iScsiName(volume.get_iScsiName());
commands.add(cmd);
}
}
}
return commands;
}
@Override
public Pair<Boolean, Long> getCommandHostDelegation(long hostId, Command cmd) {
boolean isCopyCommand = cmd instanceof CopyCommand;
Pair<Boolean, Long> defaultHostToExecuteCommands = super.getCommandHostDelegation(hostId, cmd);
if (!isCopyCommand) {
logger.debug("We are returning the default host to execute commands because the command is not of Copy type.");
return defaultHostToExecuteCommands;
}
CopyCommand copyCommand = (CopyCommand)cmd;
DataTO srcData = copyCommand.getSrcTO();
DataTO destData = copyCommand.getDestTO();
boolean isSourceDataHypervisorXenServer = srcData.getHypervisorType() == HypervisorType.XenServer;
if (!isSourceDataHypervisorXenServer) {
logger.debug("We are returning the default host to execute commands because the target hypervisor of the source data is not XenServer.");
return defaultHostToExecuteCommands;
}
// only now can we decide, now we now we're only deciding for ourselves
if (cmd instanceof StorageSubSystemCommand) {
if (s_logger.isTraceEnabled()) {
s_logger.trace(String.format("XenServer StrorageSubSystemCommand re always executed in sequence (command of type %s to host %l).", cmd.getClass(), hostId));
}
StorageSubSystemCommand c = (StorageSubSystemCommand)cmd;
c.setExecuteInSequence(true);
}
DataStoreTO srcStore = srcData.getDataStore();
DataStoreTO destStore = destData.getDataStore();
boolean isSourceAndDestinationNfsObjects = srcStore instanceof NfsTO && destStore instanceof NfsTO;
if (!isSourceAndDestinationNfsObjects) {
logger.debug("We are returning the default host to execute commands because the source and destination objects are not NFS type.");
return defaultHostToExecuteCommands;
}
boolean isSourceObjectSnapshotTypeAndDestinationObjectTemplateType = srcData.getObjectType() == DataObjectType.SNAPSHOT
&& destData.getObjectType() == DataObjectType.TEMPLATE;
if (!isSourceObjectSnapshotTypeAndDestinationObjectTemplateType) {
logger.debug("We are returning the default host to execute commands because the source and destination objects are not snapshot and template respectively.");
return defaultHostToExecuteCommands;
}
HostVO defaultHostToExecuteCommand = hostDao.findById(hostId);
HostVO hostCandidateToExecutedCommand = hostDao.findHostInZoneToExecuteCommand(defaultHostToExecuteCommand.getDataCenterId(), srcData.getHypervisorType());
hostDao.loadDetails(hostCandidateToExecutedCommand);
String hypervisorVersion = hostCandidateToExecutedCommand.getHypervisorVersion();
if (StringUtils.isBlank(hypervisorVersion)) {
logger.debug("We are returning the default host to execute commands because the hypervisor version is blank.");
return defaultHostToExecuteCommands;
}
boolean isXenServer610 = StringUtils.equals(hypervisorVersion, "6.1.0");
if (isXenServer610) {
logger.debug("We are returning the default host to execute commands because the hypervisor version is 6.1.0.");
return defaultHostToExecuteCommands;
}
String snapshotHotFixVersion = hostCandidateToExecutedCommand.getDetail(XenserverConfigs.XS620HotFix);
boolean isXenServer620 = StringUtils.equals(hypervisorVersion, "6.2.0");
if (isXenServer620 && !StringUtils.equalsIgnoreCase(XenserverConfigs.XSHotFix62ESP1004, snapshotHotFixVersion)) {
logger.debug(String.format("We are returning the default host to execute commands because the hypervisor version is not 6.2.0 with hotfix ESP1004 [hypervisorVersion=%s, hotfixVersion=%s]", hypervisorVersion, snapshotHotFixVersion));
return defaultHostToExecuteCommands;
}
logger.debug(String.format("We are changing the hostId to executed command from %d to %d.", hostId, hostCandidateToExecutedCommand.getId()));
return new Pair<Boolean, Long>(Boolean.TRUE, new Long(hostCandidateToExecutedCommand.getId()));
}
@Override
public String getConfigComponentName() {
return XenServerGuru.class.getSimpleName();
}
@Override
public ConfigKey<?>[] getConfigKeys() {
return new ConfigKey<?>[] {MaxNumberOfVCPUSPerVM};
}
}