package org.ovirt.engine.core.bll;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils;
import org.ovirt.engine.core.bll.context.CompensationContext;
import org.ovirt.engine.core.common.businessentities.DiskImage;
import org.ovirt.engine.core.common.businessentities.VM;
import org.ovirt.engine.core.common.businessentities.VMStatus;
import org.ovirt.engine.core.common.businessentities.VmDynamic;
import org.ovirt.engine.core.common.businessentities.VmNetworkInterface;
import org.ovirt.engine.core.common.businessentities.VmOsType;
import org.ovirt.engine.core.common.businessentities.VmStatic;
import org.ovirt.engine.core.common.config.Config;
import org.ovirt.engine.core.common.config.ConfigValues;
import org.ovirt.engine.core.common.errors.VdcBLLException;
import org.ovirt.engine.core.common.errors.VdcBllErrors;
import org.ovirt.engine.core.common.utils.VmValidationUtils;
import org.ovirt.engine.core.common.vdscommands.IrsBaseVDSCommandParameters;
import org.ovirt.engine.core.common.vdscommands.SetVmStatusVDSCommandParameters;
import org.ovirt.engine.core.common.vdscommands.VDSCommandType;
import org.ovirt.engine.core.compat.Guid;
import org.ovirt.engine.core.compat.LogCompat;
import org.ovirt.engine.core.compat.LogFactoryCompat;
import org.ovirt.engine.core.compat.RpmVersion;
import org.ovirt.engine.core.compat.Version;
import org.ovirt.engine.core.dal.VdcBllMessages;
import org.ovirt.engine.core.dal.dbbroker.DbFacade;
import org.ovirt.engine.core.utils.ObjectIdentityChecker;
import org.ovirt.engine.core.utils.linq.LinqUtils;
import org.ovirt.engine.core.utils.linq.Predicate;
import org.ovirt.engine.core.utils.transaction.TransactionMethod;
import org.ovirt.engine.core.utils.transaction.TransactionSupport;
public class VmHandler {
public static ObjectIdentityChecker mUpdateVmsStatic;
/**
* Initialize static list containers, for identity and permission check. The initialization should be executed
* before calling ObjectIdentityChecker.
*
* @see Backend#InitHandlers
*/
public static void Init() {
mUpdateVmsStatic = new ObjectIdentityChecker(VmHandler.class,
java.util.Arrays.asList(new String[] { "VM", "VmStatic", "VmDynamic" }), VMStatus.class);
mUpdateVmsStatic.AddPermittedFields(new String[] { "vm_name", "description", "domain", "os", "osType",
"creation_date", "num_of_monitors", "usb_policy", "is_auto_suspend", "auto_startup",
"dedicated_vm_for_vds", "default_display_type", "priority", "default_boot_sequence", "initrd_url",
"kernel_url", "kernel_params", "migrationSupport", "minAllocatedMem" });
mUpdateVmsStatic.AddFields(
java.util.Arrays.asList(new Enum[] { VMStatus.Down }),
Arrays.asList(new String[] { "vds_group_id", "time_zone", "is_stateless", "nice_level", "mem_size_mb",
"num_of_sockets", "cpu_per_socket", "iso_path", "userDefinedProperties", "predefinedProperties", "customProperties" }));
}
/**
* Verifies the add vm command .
*
* @param reasons
* The reasons.
* @param vmsCount
* The VMS count.
* @param vmTemplateId
* The vm template id.
* @return
*/
public static boolean VerifyAddVm(java.util.ArrayList<String> reasons,
int vmsCount,
Object vmTemplateId,
Guid storagePoolId,
Guid storageDomainId,
boolean checkVmTemplateImages,
boolean checkTemplateLock,
int vmPriority) {
boolean returnValue = true;
if (MacPoolManager.getInstance().getavailableMacsCount() < vmsCount) {
if (reasons != null) {
reasons.add(VdcBllMessages.MAC_POOL_NOT_ENOUGH_MAC_ADDRESSES.toString());
}
returnValue = false;
} else {
boolean isValid = ((Boolean) Backend.getInstance().getResourceManager()
.RunVdsCommand(VDSCommandType.IsValid, new IrsBaseVDSCommandParameters(storagePoolId))
.getReturnValue()).booleanValue();
if (isValid) {
if (!VmTemplateCommand.IsVmPriorityValueLegal(vmPriority, reasons)) {
returnValue = false;
} else if (checkVmTemplateImages) {
returnValue = VmTemplateCommand.isVmTemplateImagesReady((Guid) vmTemplateId, storageDomainId,
reasons, true, checkTemplateLock, true, true);
}
} else {
if (reasons != null) {
reasons.add(VdcBllMessages.IMAGE_REPOSITORY_NOT_FOUND.toString());
}
returnValue = false;
}
}
return returnValue;
}
public static boolean isVmWithSameNameExistStatic(String vmName) {
List<VmStatic> vmStatic = DbFacade.getInstance().getVmStaticDAO().getAllByName(vmName);
return (vmStatic.size() != 0);
}
public static void QueueAndLockVm(Guid vmId) {
LockVm(vmId);
}
/**
* Lock the VM in a new transaction, saving compensation data of the old status.
*
* @param vm
* The VM to lock.
* @param compensationContext
* Used to save the old VM status, for compensation purposes.
*/
public static void LockVm(final VmDynamic vm, final CompensationContext compensationContext) {
TransactionSupport.executeInNewTransaction(new TransactionMethod<Void>() {
@Override
public Void runInTransaction() {
compensationContext.snapshotEntityStatus(vm, vm.getstatus());
LockVm(vm.getId());
compensationContext.stateChanged();
return null;
}
});
}
/**
* Check VM status before locking it, If VM status is not down, we throw an exception.
*
* @param status
* - The status of the VM
*/
private static void checkStatusBeforeLock(VMStatus status) {
if (status == VMStatus.ImageLocked) {
log.error("VM status cannot change to image locked, since it is already locked");
throw new VdcBLLException(VdcBllErrors.IRS_IMAGE_STATUS_ILLEGAL);
}
}
/**
* Lock VM after check its status, If VM status is locked, we throw an exception.
*
* @param status
* - The status of the VM
* @param vmId
* - The ID of the VM.
*/
public static void checkStatusAndLockVm(Guid vmId) {
VmDynamic vmDynamic = DbFacade.getInstance().getVmDynamicDAO().get(vmId);
checkStatusBeforeLock(vmDynamic.getstatus());
LockVm(vmId);
}
/**
* Lock VM with compensation, after checking its status, If VM status is locked, we throw an exception.
*
* @param status
* - The status of the VM
* @param vmId
* - The ID of the VM, which we want to lock.
* @param compensationContext
* - Used to save the old VM status for compensation purposes.
*/
public static void checkStatusAndLockVm(Guid vmId, CompensationContext compensationContext) {
VmDynamic vmDynamic = DbFacade.getInstance().getVmDynamicDAO().get(vmId);
checkStatusBeforeLock(vmDynamic.getstatus());
LockVm(vmDynamic, compensationContext);
}
public static void LockVm(Guid vmId) {
Backend.getInstance()
.getResourceManager()
.RunVdsCommand(VDSCommandType.SetVmStatus,
new SetVmStatusVDSCommandParameters(vmId, VMStatus.ImageLocked));
}
/**
* Unlock the VM in a new transaction, saving compensation data of the old status.
*
* @param vm
* The VM to unlock.
* @param compensationContext
* Used to save the old VM status, for compensation purposes.
*/
public static void unlockVm(final VmDynamic vm, final CompensationContext compensationContext) {
TransactionSupport.executeInNewTransaction(new TransactionMethod<Void>() {
@Override
public Void runInTransaction() {
compensationContext.snapshotEntityStatus(vm, vm.getstatus());
UnLockVm(vm.getId());
compensationContext.stateChanged();
return null;
}
});
}
public static void UnLockVm(Guid vmId) {
VM vm = DbFacade.getInstance().getVmDAO().getById(vmId);
if (vm.getstatus() == VMStatus.ImageLocked) {
Backend.getInstance()
.getResourceManager()
.RunVdsCommand(VDSCommandType.SetVmStatus, new SetVmStatusVDSCommandParameters(vmId, VMStatus.Down));
} else {
log.errorFormat("Trying to unlock vm {0} in status {1} - not moving to down!", vm.getvm_name(),
vm.getstatus());
}
}
public static void MarkVmAsIllegal(Guid vmId) {
Backend.getInstance()
.getResourceManager()
.RunVdsCommand(VDSCommandType.SetVmStatus,
new SetVmStatusVDSCommandParameters(vmId, VMStatus.ImageIllegal));
}
public static void updateDisksFromDb(VM vm) {
List<DiskImage> imageList = DbFacade.getInstance().getDiskImageDAO().getAllForVm(vm.getvm_guid());
for (DiskImage image : imageList) {
if (image.getactive() != null && image.getactive()) {
vm.getDiskMap().put(image.getinternal_drive_mapping(), image);
vm.getDiskList().add(image);
}
}
}
private static Version GetApplicationVersion(final String part, final String appName) {
try {
return new RpmVersion(part, getAppName(part, appName), true);
} catch (Exception e) {
log.debugFormat("Failed to create rpm version object, part: {0} appName: {1}, error: {2}",
part,
appName,
e.toString());
return null;
}
}
private static String getAppName(final String part, final String appName) {
if (StringUtils.contains(part, appName + "64")) { // 64 bit Agent has extension
// to its name.
return appName + "64";
} else {
return appName;
}
}
/**
* Updates the {@link VM}'s {@link VM#getGuestAgentVersion()} and {@link VM#getSpiceDriverVersion()} based on the
* VM's {@link VM#getapp_list()} property.
*
* @param vm
* the VM
*/
public static void UpdateVmGuestAgentVersion(final VM vm) {
if (vm.getapp_list() != null) {
final String[] parts = vm.getapp_list().split("[,]", -1);
if (parts != null && parts.length != 0) {
final String agentAppName = Config.<String> GetValue(ConfigValues.AgentAppName);
final Map<String, String> spiceDriversInGuest =
Config.<Map<String, String>> GetValue(ConfigValues.SpiceDriverNameInGuest);
final String spiceDriverInGuest =
spiceDriversInGuest.get(ObjectUtils.toString(vm.getos().getOsType()).toLowerCase());
for (final String part : parts) {
if (StringUtils.containsIgnoreCase(part, agentAppName)) {
vm.setGuestAgentVersion(GetApplicationVersion(part,
agentAppName));
}
if (StringUtils.containsIgnoreCase(part,
spiceDriverInGuest)) {
vm.setSpiceDriverVersion(GetApplicationVersion(part,
spiceDriverInGuest));
}
}
}
}
}
/**
* Checks the validity of the given memory size according to OS type.
*
* @param osType
* Type of the os.
* @param memSizeInMB
* The mem size in MB.
* @param reasons
* The reasons.VdsGroups
* @return
*/
public static boolean isMemorySizeLegal(VmOsType osType, int memSizeInMB, java.util.ArrayList<String> reasons,
String clsuter_version) {
boolean result = VmValidationUtils.isMemorySizeLegal(osType, memSizeInMB, clsuter_version);
if (!result) {
reasons.add(VdcBllMessages.ACTION_TYPE_FAILED_ILLEGAL_MEMORY_SIZE.toString());
reasons.add(String.format("$minMemorySize %s", VmValidationUtils.getMinMemorySizeInMb()));
reasons.add(String.format("$maxMemorySize %s", VmValidationUtils.getMaxMemorySizeInMb(osType, clsuter_version)));
}
return result;
}
/**
* Check if the interface name is not duplicate in the list of interfaces.
*
* @param interfaces
* - List of interfaces the VM/Template got.
* @param interfaceName
* - Candidate for interface name.
* @param messages
* - Messages for CanDoAction().
* @return - True , if name is valid, false, if name already exist.
*/
public static boolean IsNotDuplicateInterfaceName(List<VmNetworkInterface> interfaces,
final String interfaceName,
List<String> messages) {
// Interface iface = interfaces.FirstOrDefault(i => i.name ==
// AddVmInterfaceParameters.Interface.name);
VmNetworkInterface iface = LinqUtils.firstOrNull(interfaces, new Predicate<VmNetworkInterface>() {
@Override
public boolean eval(VmNetworkInterface i) {
return i.getName().equals(interfaceName);
}
});
if (iface != null) {
messages.add(VdcBllMessages.NETWORK_INTERFACE_NAME_ALREAY_IN_USE.name());
return false;
}
return true;
}
private static LogCompat log = LogFactoryCompat.getLog(VmHandler.class);
}