Refactor and improvements for method com.cloud.hypervisor.kvm.resource.LibvirtComputingResource.createVMFromSpec() (#5149)

* Refactor method createVMFromSpec

* Add unit tests

* Fix test

* Extract if block to method for add extra configs to VM Domain XML

* Split travis tests trying to isolate which test is causing an error

* Override toString() method

* Update documentation

* Fix checkstyle error (line with trailing spaces)

* Change VirtualMachineTO print of object

* Add try except to find message error. Remove after test

* Fix indent

* Trying to understanding why is happening in this code

* Refactor method createVMFromSpec

* Add unit tests

* Fix test

* Extract if block to method for add extra configs to VM Domain XML

* Split travis tests trying to isolate which test is causing an error

* Override toString() method

* Update documentation

* Fix checkstyle error (line with trailing spaces)

* Remove unnecessary comment

* Revert travis tests

Co-authored-by: SadiJr <17a0db2854@firemailbox.club>
This commit is contained in:
SadiJr 2021-07-21 15:07:25 -03:00 committed by GitHub
parent eb3acc334b
commit eff2da2518
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 829 additions and 251 deletions

View File

@ -413,4 +413,9 @@ public class VirtualMachineTO {
public void setDeployAsIsInfo(DeployAsIsInfoTO deployAsIsInfo) { public void setDeployAsIsInfo(DeployAsIsInfoTO deployAsIsInfo) {
this.deployAsIsInfo = deployAsIsInfo; this.deployAsIsInfo = deployAsIsInfo;
} }
@Override
public String toString() {
return String.format("VM {id: \"%s\", name: \"%s\", uuid: \"%s\", type: \"%s\"}", id, name, uuid, type);
}
} }

View File

@ -209,6 +209,71 @@ import com.google.common.base.Strings;
public class LibvirtComputingResource extends ServerResourceBase implements ServerResource, VirtualRouterDeployer { public class LibvirtComputingResource extends ServerResourceBase implements ServerResource, VirtualRouterDeployer {
private static final Logger s_logger = Logger.getLogger(LibvirtComputingResource.class); private static final Logger s_logger = Logger.getLogger(LibvirtComputingResource.class);
private static final String LEGACY = "legacy";
private static final String SECURE = "secure";
/**
* Machine type.
*/
private static final String PC = "pc";
private static final String VIRT = "virt";
/**
* Possible devices to add to VM.
*/
private static final String TABLET = "tablet";
private static final String USB = "usb";
private static final String MOUSE = "mouse";
private static final String KEYBOARD = "keyboard";
/**
* Policies used by VM.
*/
private static final String RESTART = "restart";
private static final String DESTROY = "destroy";
private static final String KVMCLOCK = "kvmclock";
private static final String HYPERVCLOCK = "hypervclock";
private static final String WINDOWS = "Windows";
private static final String Q35 = "q35";
private static final String PTY = "pty";
private static final String VNC = "vnc";
/**
* Acronym of System Management Mode. Perform low-level system management operations while an OS is running.
*/
private static final String SMM = "smm";
/**
* Acronym of Advanced Configuration and Power Interface.<br>
* Provides an open standard that operating systems can use to discover and configure
* computer hardware components, to perform power management.
*/
private static final String ACPI = "acpi";
/**
* Acronym of Advanced Programmable Interrupt Controllers.<br>
* With an I/O APIC, operating systems can use more than 16 interrupt requests (IRQs)
* and therefore avoid IRQ sharing for improved reliability.
*/
private static final String APIC = "apic";
/**
* Acronym of Physical Address Extension. Feature implemented in modern x86 processors.<br>
* PAE extends memory addressing capabilities, allowing more than 4 GB of random access memory (RAM) to be used.
*/
private static final String PAE = "pae";
/**
* Libvirt supports guest CPU mode since 0.9.10.
*/
private static final int MIN_LIBVIRT_VERSION_FOR_GUEST_CPU_MODE = 9010;
/**
* The CPU tune element provides details of the CPU tunable parameters for the domain.<br>
* It is supported since Libvirt 0.9.0
*/
private static final int MIN_LIBVIRT_VERSION_FOR_GUEST_CPU_TUNE = 9000;
/**
* Constant that defines ARM64 (aarch64) guest architectures.
*/
private static final String AARCH64 = "aarch64";
private String _modifyVlanPath; private String _modifyVlanPath;
private String _versionstringpath; private String _versionstringpath;
private String _patchScriptPath; private String _patchScriptPath;
@ -2239,8 +2304,13 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
} }
} }
/**
* Creates VM KVM definitions from virtual machine transfer object specifications.
*/
public LibvirtVMDef createVMFromSpec(final VirtualMachineTO vmTO) { public LibvirtVMDef createVMFromSpec(final VirtualMachineTO vmTO) {
final LibvirtVMDef vm = new LibvirtVMDef(); s_logger.debug(String.format("Creating VM from specifications [%s]", vmTO.toString()));
LibvirtVMDef vm = new LibvirtVMDef();
vm.setDomainName(vmTO.getName()); vm.setDomainName(vmTO.getName());
String uuid = vmTO.getUuid(); String uuid = vmTO.getUuid();
uuid = getUuid(uuid); uuid = getUuid(uuid);
@ -2251,215 +2321,311 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
Map<String, String> customParams = vmTO.getDetails(); Map<String, String> customParams = vmTO.getDetails();
boolean isUefiEnabled = false; boolean isUefiEnabled = false;
boolean isSecureBoot = false; boolean isSecureBoot = false;
String bootMode =null; String bootMode = null;
if (MapUtils.isNotEmpty(customParams) && customParams.containsKey(GuestDef.BootType.UEFI.toString())) { if (MapUtils.isNotEmpty(customParams) && customParams.containsKey(GuestDef.BootType.UEFI.toString())) {
isUefiEnabled = true; isUefiEnabled = true;
bootMode = customParams.get(GuestDef.BootType.UEFI.toString()); s_logger.debug(String.format("Enabled UEFI for VM UUID [%s].", uuid));
if (StringUtils.isNotBlank(bootMode) && "secure".equalsIgnoreCase(bootMode)) {
if (isSecureMode(customParams.get(GuestDef.BootType.UEFI.toString()))) {
s_logger.debug(String.format("Enabled Secure Boot for VM UUID [%s].", uuid));
isSecureBoot = true; isSecureBoot = true;
} }
} }
Map<String, String> extraConfig = vmTO.getExtraConfig(); Map<String, String> extraConfig = vmTO.getExtraConfig();
if (dpdkSupport && (!extraConfig.containsKey(DpdkHelper.DPDK_NUMA) || !extraConfig.containsKey(DpdkHelper.DPDK_HUGE_PAGES))) { if (dpdkSupport && (!extraConfig.containsKey(DpdkHelper.DPDK_NUMA) || !extraConfig.containsKey(DpdkHelper.DPDK_HUGE_PAGES))) {
s_logger.info("DPDK is enabled but it needs extra configurations for CPU NUMA and Huge Pages for VM deployment"); s_logger.info(String.format("DPDK is enabled for VM [%s], but it needs extra configurations for CPU NUMA and Huge Pages for VM deployment.", vmTO.toString()));
}
configureVM(vmTO, vm, customParams, isUefiEnabled, isSecureBoot, bootMode, extraConfig, uuid);
return vm;
} }
final GuestDef guest = new GuestDef(); /**
* Configures created VM from specification, adding the necessary components to VM.
*/
private void configureVM(VirtualMachineTO vmTO, LibvirtVMDef vm, Map<String, String> customParams, boolean isUefiEnabled, boolean isSecureBoot, String bootMode,
Map<String, String> extraConfig, String uuid) {
s_logger.debug(String.format("Configuring VM with UUID [%s].", uuid));
if (HypervisorType.LXC == _hypervisorType && VirtualMachine.Type.User == vmTO.getType()) { GuestDef guest = createGuestFromSpec(vmTO, vm, uuid, customParams);
// LXC domain is only valid for user VMs. Use KVM for system VMs. if (isUefiEnabled) {
guest.setGuestType(GuestDef.GuestType.LXC); configureGuestIfUefiEnabled(isSecureBoot, bootMode, guest);
vm.setHvsType(HypervisorType.LXC.toString().toLowerCase());
} else {
guest.setGuestType(GuestDef.GuestType.KVM);
vm.setHvsType(HypervisorType.KVM.toString().toLowerCase());
vm.setLibvirtVersion(_hypervisorLibvirtVersion);
vm.setQemuVersion(_hypervisorQemuVersion);
} }
vm.addComp(guest);
vm.addComp(createGuestResourceDef(vmTO));
int vcpus = vmTO.getCpus();
if (!extraConfig.containsKey(DpdkHelper.DPDK_NUMA)) {
vm.addComp(createCpuModeDef(vmTO, vcpus));
}
if (_hypervisorLibvirtVersion >= MIN_LIBVIRT_VERSION_FOR_GUEST_CPU_TUNE) {
vm.addComp(createCpuTuneDef(vmTO));
}
FeaturesDef features = createFeaturesDef(customParams, isUefiEnabled, isSecureBoot);
enlightenWindowsVm(vmTO, features);
vm.addComp(features);
vm.addComp(createTermPolicy());
vm.addComp(createClockDef(vmTO));
vm.addComp(createDevicesDef(vmTO, guest, vcpus, isUefiEnabled));
addExtraConfigsToVM(vmTO, vm, extraConfig);
}
/**
* Adds extra configuration to User VM Domain XML before starting.
*/
private void addExtraConfigsToVM(VirtualMachineTO vmTO, LibvirtVMDef vm, Map<String, String> extraConfig) {
if (MapUtils.isNotEmpty(extraConfig) && VirtualMachine.Type.User.equals(vmTO.getType())) {
s_logger.debug(String.format("Appending extra configuration data [%s] to guest VM [%s] domain XML.", extraConfig, vmTO.toString()));
addExtraConfigComponent(extraConfig, vm);
}
}
/**
* Adds devices components to VM.
*/
protected DevicesDef createDevicesDef(VirtualMachineTO vmTO, GuestDef guest, int vcpus, boolean isUefiEnabled) {
DevicesDef devices = new DevicesDef();
devices.setEmulatorPath(_hypervisorPath);
devices.setGuestType(guest.getGuestType());
devices.addDevice(createSerialDef());
if (_rngEnable) {
devices.addDevice(createRngDef());
}
devices.addDevice(createChannelDef(vmTO));
devices.addDevice(createWatchDogDef());
devices.addDevice(createVideoDef());
devices.addDevice(createConsoleDef());
devices.addDevice(createGraphicDef(vmTO));
devices.addDevice(createTabletInputDef());
if (isGuestAarch64()) {
createArm64UsbDef(devices);
}
DiskDef.DiskBus busT = getDiskModelFromVMDetail(vmTO);
if (busT == null) {
busT = getGuestDiskModel(vmTO.getPlatformEmulator(), isUefiEnabled);
}
if (busT == DiskDef.DiskBus.SCSI) {
devices.addDevice(createSCSIDef(vcpus));
}
return devices;
}
protected WatchDogDef createWatchDogDef() {
return new WatchDogDef(_watchDogAction, _watchDogModel);
}
protected void createArm64UsbDef(DevicesDef devices) {
devices.addDevice(new InputDef(KEYBOARD, USB));
devices.addDevice(new InputDef(MOUSE, USB));
devices.addDevice(new LibvirtVMDef.USBDef((short)0, 0, 5, 0, 0));
}
protected InputDef createTabletInputDef() {
return new InputDef(TABLET, USB);
}
/**
* Creates a Libvirt Graphic Definition with the VM's password and VNC address.
*/
protected GraphicDef createGraphicDef(VirtualMachineTO vmTO) {
return new GraphicDef(VNC, (short)0, true, vmTO.getVncAddr(), vmTO.getVncPassword(), null);
}
/**
* Adds a Virtio channel for the Qemu Guest Agent tools.
*/
protected ChannelDef createChannelDef(VirtualMachineTO vmTO) {
File virtIoChannel = Paths.get(_qemuSocketsPath.getPath(), vmTO.getName() + "." + _qemuGuestAgentSocketName).toFile();
return new ChannelDef(_qemuGuestAgentSocketName, ChannelDef.ChannelType.UNIX, virtIoChannel);
}
/**
* Creates Virtio SCSI controller. <br>
* The respective Virtio SCSI XML definition is generated only if the VM's Disk Bus is of ISCSI.
*/
protected SCSIDef createSCSIDef(int vcpus) {
return new SCSIDef((short)0, 0, 0, 9, 0, vcpus);
}
protected ConsoleDef createConsoleDef() {
return new ConsoleDef(PTY, null, null, (short)0);
}
protected VideoDef createVideoDef() {
return new VideoDef(_videoHw, _videoRam);
}
protected RngDef createRngDef() {
return new RngDef(_rngPath, _rngBackendModel, _rngRateBytes, _rngRatePeriod);
}
protected SerialDef createSerialDef() {
return new SerialDef(PTY, null, (short)0);
}
protected ClockDef createClockDef(final VirtualMachineTO vmTO) {
ClockDef clock = new ClockDef();
if (org.apache.commons.lang.StringUtils.startsWith(vmTO.getOs(), WINDOWS)) {
clock.setClockOffset(ClockDef.ClockOffset.LOCALTIME);
clock.setTimer(HYPERVCLOCK, null, null);
} else if ((vmTO.getType() != VirtualMachine.Type.User || isGuestPVEnabled(vmTO.getOs())) && _hypervisorLibvirtVersion >= MIN_LIBVIRT_VERSION_FOR_GUEST_CPU_MODE) {
clock.setTimer(KVMCLOCK, null, null, _noKvmClock);
}
return clock;
}
protected TermPolicy createTermPolicy() {
TermPolicy term = new TermPolicy();
term.setCrashPolicy(DESTROY);
term.setPowerOffPolicy(DESTROY);
term.setRebootPolicy(RESTART);
return term;
}
protected FeaturesDef createFeaturesDef(Map<String, String> customParams, boolean isUefiEnabled, boolean isSecureBoot) {
FeaturesDef features = new FeaturesDef();
features.addFeatures(PAE);
features.addFeatures(APIC);
features.addFeatures(ACPI);
if (isUefiEnabled && isSecureBoot) {
features.addFeatures(SMM);
}
return features;
}
/**
* A 4.0.X/4.1.X management server doesn't send the correct JSON
* command for getMinSpeed, it only sends a 'speed' field.<br>
* So, to create a cpu tune, if getMinSpeed() returns null we fall back to getSpeed().<br>
* This way a >4.1 agent can work communicate a <=4.1 management server.<br>
* This change is due to the overcommit feature in 4.2.
*/
protected CpuTuneDef createCpuTuneDef(VirtualMachineTO vmTO) {
CpuTuneDef ctd = new CpuTuneDef();
int shares = vmTO.getCpus() * (vmTO.getMinSpeed() != null ? vmTO.getMinSpeed() : vmTO.getSpeed());
ctd.setShares(shares);
setQuotaAndPeriod(vmTO, ctd);
return ctd;
}
private CpuModeDef createCpuModeDef(VirtualMachineTO vmTO, int vcpus) {
final CpuModeDef cmd = new CpuModeDef();
cmd.setMode(_guestCpuMode);
cmd.setModel(_guestCpuModel);
if (VirtualMachine.Type.User.equals(vmTO.getType())) {
cmd.setFeatures(_cpuFeatures);
}
setCpuTopology(cmd, vcpus, vmTO.getDetails());
return cmd;
}
/**
* Creates guest resources based in VM specification.
*/
protected GuestResourceDef createGuestResourceDef(VirtualMachineTO vmTO) {
GuestResourceDef grd = new GuestResourceDef();
grd.setMemorySize(vmTO.getMaxRam() / 1024);
if (vmTO.getMinRam() != vmTO.getMaxRam() && !_noMemBalloon) {
grd.setMemBalloning(true);
grd.setCurrentMem(vmTO.getMinRam() / 1024);
}
grd.setVcpuNum(vmTO.getCpus());
return grd;
}
private void configureGuestIfUefiEnabled(boolean isSecureBoot, String bootMode, GuestDef guest) {
setGuestLoader(bootMode, SECURE, guest, GuestDef.GUEST_LOADER_SECURE);
setGuestLoader(bootMode, LEGACY, guest, GuestDef.GUEST_LOADER_LEGACY);
if (isUefiPropertieNotNull(GuestDef.GUEST_NVRAM_PATH)) {
guest.setNvram(_uefiProperties.getProperty(GuestDef.GUEST_NVRAM_PATH));
}
if (isSecureBoot && isUefiPropertieNotNull(GuestDef.GUEST_NVRAM_TEMPLATE_SECURE) && SECURE.equalsIgnoreCase(bootMode)) {
guest.setNvramTemplate(_uefiProperties.getProperty(GuestDef.GUEST_NVRAM_TEMPLATE_SECURE));
} else if (isUefiPropertieNotNull(GuestDef.GUEST_NVRAM_TEMPLATE_LEGACY)) {
guest.setNvramTemplate(_uefiProperties.getProperty(GuestDef.GUEST_NVRAM_TEMPLATE_LEGACY));
}
}
private void setGuestLoader(String bootMode, String mode, GuestDef guest, String propertie) {
if (isUefiPropertieNotNull(propertie) && mode.equalsIgnoreCase(bootMode)) {
guest.setLoader(_uefiProperties.getProperty(propertie));
}
}
private boolean isUefiPropertieNotNull(String propertie) {
return _uefiProperties.getProperty(propertie) != null;
}
private boolean isGuestAarch64() {
return AARCH64.equals(_guestCpuArch);
}
/**
* Creates a guest definition from a VM specification.
*/
protected GuestDef createGuestFromSpec(VirtualMachineTO vmTO, LibvirtVMDef vm, String uuid, Map<String, String> customParams) {
GuestDef guest = new GuestDef();
configureGuestAndVMHypervisorType(vmTO, vm, guest);
guest.setGuestArch(_guestCpuArch != null ? _guestCpuArch : vmTO.getArch()); guest.setGuestArch(_guestCpuArch != null ? _guestCpuArch : vmTO.getArch());
guest.setMachineType(_guestCpuArch != null && _guestCpuArch.equals("aarch64") ? "virt" : "pc"); guest.setMachineType(isGuestAarch64() ? VIRT : PC);
guest.setBootType(GuestDef.BootType.BIOS); guest.setBootType(GuestDef.BootType.BIOS);
if (MapUtils.isNotEmpty(customParams) && customParams.containsKey(GuestDef.BootType.UEFI.toString())) { if (MapUtils.isNotEmpty(customParams) && customParams.containsKey(GuestDef.BootType.UEFI.toString())) {
guest.setBootType(GuestDef.BootType.UEFI); guest.setBootType(GuestDef.BootType.UEFI);
guest.setBootMode(GuestDef.BootMode.LEGACY); guest.setBootMode(GuestDef.BootMode.LEGACY);
guest.setMachineType("q35"); guest.setMachineType(Q35);
if (StringUtils.isNotBlank(customParams.get(GuestDef.BootType.UEFI.toString())) && "secure".equalsIgnoreCase(customParams.get(GuestDef.BootType.UEFI.toString()))) { if (SECURE.equalsIgnoreCase(customParams.get(GuestDef.BootType.UEFI.toString()))) {
guest.setBootMode(GuestDef.BootMode.SECURE); // setting to secure mode guest.setBootMode(GuestDef.BootMode.SECURE);
} }
} }
guest.setUuid(uuid); guest.setUuid(uuid);
guest.setBootOrder(GuestDef.BootOrder.CDROM); guest.setBootOrder(GuestDef.BootOrder.CDROM);
guest.setBootOrder(GuestDef.BootOrder.HARDISK); guest.setBootOrder(GuestDef.BootOrder.HARDISK);
return guest;
if (isUefiEnabled) {
if (_uefiProperties.getProperty(GuestDef.GUEST_LOADER_SECURE) != null && "secure".equalsIgnoreCase(bootMode)) {
guest.setLoader(_uefiProperties.getProperty(GuestDef.GUEST_LOADER_SECURE));
} }
if (_uefiProperties.getProperty(GuestDef.GUEST_LOADER_LEGACY) != null && "legacy".equalsIgnoreCase(bootMode)) { protected void configureGuestAndVMHypervisorType(VirtualMachineTO vmTO, LibvirtVMDef vm, GuestDef guest) {
guest.setLoader(_uefiProperties.getProperty(GuestDef.GUEST_LOADER_LEGACY)); if (HypervisorType.LXC == _hypervisorType && VirtualMachine.Type.User.equals(vmTO.getType())) {
} configureGuestAndUserVMToUseLXC(vm, guest);
if (_uefiProperties.getProperty(GuestDef.GUEST_NVRAM_PATH) != null) {
guest.setNvram(_uefiProperties.getProperty(GuestDef.GUEST_NVRAM_PATH));
}
if (isSecureBoot) {
if (_uefiProperties.getProperty(GuestDef.GUEST_NVRAM_TEMPLATE_SECURE) != null && "secure".equalsIgnoreCase(bootMode)) {
guest.setNvramTemplate(_uefiProperties.getProperty(GuestDef.GUEST_NVRAM_TEMPLATE_SECURE));
}
} else { } else {
if (_uefiProperties.getProperty(GuestDef.GUEST_NVRAM_TEMPLATE_LEGACY) != null) { configureGuestAndSystemVMToUseKVM(vm, guest);
guest.setNvramTemplate(_uefiProperties.getProperty(GuestDef.GUEST_NVRAM_TEMPLATE_LEGACY));
}
} }
} }
vm.addComp(guest);
final GuestResourceDef grd = new GuestResourceDef();
if (vmTO.getMinRam() != vmTO.getMaxRam() && !_noMemBalloon) {
grd.setMemBalloning(true);
grd.setCurrentMem(vmTO.getMinRam() / 1024);
grd.setMemorySize(vmTO.getMaxRam() / 1024);
} else {
grd.setMemorySize(vmTO.getMaxRam() / 1024);
}
final int vcpus = vmTO.getCpus();
grd.setVcpuNum(vcpus);
vm.addComp(grd);
if (!extraConfig.containsKey(DpdkHelper.DPDK_NUMA)) {
final CpuModeDef cmd = new CpuModeDef();
cmd.setMode(_guestCpuMode);
cmd.setModel(_guestCpuModel);
if (vmTO.getType() == VirtualMachine.Type.User) {
cmd.setFeatures(_cpuFeatures);
}
setCpuTopology(cmd, vcpus, vmTO.getDetails());
vm.addComp(cmd);
}
if (_hypervisorLibvirtVersion >= 9000) {
final CpuTuneDef ctd = new CpuTuneDef();
/** /**
A 4.0.X/4.1.X management server doesn't send the correct JSON * KVM domain is only valid for system VMs. Use LXC for user VMs.
command for getMinSpeed, it only sends a 'speed' field.
So if getMinSpeed() returns null we fall back to getSpeed().
This way a >4.1 agent can work communicate a <=4.1 management server
This change is due to the overcommit feature in 4.2
*/ */
if (vmTO.getMinSpeed() != null) { private void configureGuestAndSystemVMToUseKVM(LibvirtVMDef vm, GuestDef guest) {
ctd.setShares(vmTO.getCpus() * vmTO.getMinSpeed()); guest.setGuestType(GuestDef.GuestType.KVM);
} else { vm.setHvsType(HypervisorType.KVM.toString().toLowerCase());
ctd.setShares(vmTO.getCpus() * vmTO.getSpeed()); vm.setLibvirtVersion(_hypervisorLibvirtVersion);
} vm.setQemuVersion(_hypervisorQemuVersion);
setQuotaAndPeriod(vmTO, ctd);
vm.addComp(ctd);
}
final FeaturesDef features = new FeaturesDef();
features.addFeatures("pae");
features.addFeatures("apic");
features.addFeatures("acpi");
if (isUefiEnabled && isSecureMode(customParams.get(GuestDef.BootType.UEFI.toString()))) {
features.addFeatures("smm");
}
//KVM hyperv enlightenment features based on OS Type
enlightenWindowsVm(vmTO, features);
vm.addComp(features);
final TermPolicy term = new TermPolicy();
term.setCrashPolicy("destroy");
term.setPowerOffPolicy("destroy");
term.setRebootPolicy("restart");
vm.addComp(term);
final ClockDef clock = new ClockDef();
if (vmTO.getOs().startsWith("Windows")) {
clock.setClockOffset(ClockDef.ClockOffset.LOCALTIME);
clock.setTimer("hypervclock", null, null);
} else if (vmTO.getType() != VirtualMachine.Type.User || isGuestPVEnabled(vmTO.getOs())) {
if (_hypervisorLibvirtVersion >= 9 * 1000 + 10) {
clock.setTimer("kvmclock", null, null, _noKvmClock);
}
}
vm.addComp(clock);
final DevicesDef devices = new DevicesDef();
devices.setEmulatorPath(_hypervisorPath);
devices.setGuestType(guest.getGuestType());
final SerialDef serial = new SerialDef("pty", null, (short)0);
devices.addDevice(serial);
if (_rngEnable) {
final RngDef rngDevice = new RngDef(_rngPath, _rngBackendModel, _rngRateBytes, _rngRatePeriod);
devices.addDevice(rngDevice);
}
/* Add a VirtIO channel for the Qemu Guest Agent tools */
File virtIoChannel = Paths.get(_qemuSocketsPath.getPath(), vmTO.getName() + "." + _qemuGuestAgentSocketName).toFile();
devices.addDevice(new ChannelDef(_qemuGuestAgentSocketName, ChannelDef.ChannelType.UNIX, virtIoChannel));
devices.addDevice(new WatchDogDef(_watchDogAction, _watchDogModel));
final VideoDef videoCard = new VideoDef(_videoHw, _videoRam);
devices.addDevice(videoCard);
final ConsoleDef console = new ConsoleDef("pty", null, null, (short)0);
devices.addDevice(console);
//add the VNC port passwd here, get the passwd from the vmInstance.
final String passwd = vmTO.getVncPassword();
final GraphicDef grap = new GraphicDef("vnc", (short)0, true, vmTO.getVncAddr(), passwd, null);
devices.addDevice(grap);
final InputDef input = new InputDef("tablet", "usb");
devices.addDevice(input);
// Add an explicit USB devices for ARM64
if (_guestCpuArch != null && _guestCpuArch.equals("aarch64")) {
devices.addDevice(new InputDef("keyboard", "usb"));
devices.addDevice(new InputDef("mouse", "usb"));
devices.addDevice(new LibvirtVMDef.USBDef((short)0, 0, 5, 0, 0));
}
DiskDef.DiskBus busT = getDiskModelFromVMDetail(vmTO);
if (busT == null) {
busT = getGuestDiskModel(vmTO.getPlatformEmulator(), isUefiEnabled);
}
// If we're using virtio scsi, then we need to add a virtual scsi controller
if (busT == DiskDef.DiskBus.SCSI) {
final SCSIDef sd = new SCSIDef((short)0, 0, 0, 9, 0, vcpus);
devices.addDevice(sd);
}
vm.addComp(devices);
// Add extra configuration to User VM Domain XML before starting
if (vmTO.getType().equals(VirtualMachine.Type.User) && MapUtils.isNotEmpty(extraConfig)) {
s_logger.info("Appending extra configuration data to guest VM domain XML");
addExtraConfigComponent(extraConfig, vm);
}
return vm;
} }
/** /**
* Add extra configurations (if any) as a String component to the domain XML * LXC domain is only valid for user VMs. Use KVM for system VMs.
*/
private void configureGuestAndUserVMToUseLXC(LibvirtVMDef vm, GuestDef guest) {
guest.setGuestType(GuestDef.GuestType.LXC);
vm.setHvsType(HypervisorType.LXC.toString().toLowerCase());
}
/**
* Adds extra configurations (if any) as a String component to the domain XML
*/ */
protected void addExtraConfigComponent(Map<String, String> extraConfig, LibvirtVMDef vm) { protected void addExtraConfigComponent(Map<String, String> extraConfig, LibvirtVMDef vm) {
if (MapUtils.isNotEmpty(extraConfig)) { if (MapUtils.isNotEmpty(extraConfig)) {

View File

@ -79,6 +79,7 @@ import org.libvirt.jna.virDomainMemoryStats;
import org.mockito.BDDMockito; import org.mockito.BDDMockito;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.Mockito; import org.mockito.Mockito;
import org.mockito.Spy;
import org.mockito.invocation.InvocationOnMock; import org.mockito.invocation.InvocationOnMock;
import org.powermock.api.mockito.PowerMockito; import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PowerMockIgnore; import org.powermock.core.classloader.annotations.PowerMockIgnore;
@ -160,11 +161,27 @@ import com.cloud.agent.api.to.VirtualMachineTO;
import com.cloud.agent.api.to.VolumeTO; import com.cloud.agent.api.to.VolumeTO;
import com.cloud.agent.resource.virtualnetwork.VirtualRoutingResource; import com.cloud.agent.resource.virtualnetwork.VirtualRoutingResource;
import com.cloud.exception.InternalErrorException; import com.cloud.exception.InternalErrorException;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.hypervisor.kvm.resource.KVMHABase.NfsStoragePool; import com.cloud.hypervisor.kvm.resource.KVMHABase.NfsStoragePool;
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.ChannelDef; import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.ChannelDef;
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.ClockDef;
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.ConsoleDef;
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.CpuTuneDef; import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.CpuTuneDef;
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DevicesDef;
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DiskDef; import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DiskDef;
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.FeaturesDef;
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.GraphicDef;
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.GuestDef;
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.GuestDef.GuestType;
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.GuestResourceDef;
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.InputDef;
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.InterfaceDef; import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.InterfaceDef;
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.RngDef;
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.SCSIDef;
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.SerialDef;
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.TermPolicy;
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.VideoDef;
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.WatchDogDef;
import com.cloud.hypervisor.kvm.resource.wrapper.LibvirtRequestWrapper; import com.cloud.hypervisor.kvm.resource.wrapper.LibvirtRequestWrapper;
import com.cloud.hypervisor.kvm.resource.wrapper.LibvirtUtilitiesHelper; import com.cloud.hypervisor.kvm.resource.wrapper.LibvirtUtilitiesHelper;
import com.cloud.hypervisor.kvm.storage.KVMPhysicalDisk; import com.cloud.hypervisor.kvm.storage.KVMPhysicalDisk;
@ -201,6 +218,8 @@ public class LibvirtComputingResourceTest {
VirtualMachineTO vmTO; VirtualMachineTO vmTO;
@Mock @Mock
LibvirtVMDef vmDef; LibvirtVMDef vmDef;
@Spy
private LibvirtComputingResource libvirtComputingResourceSpy = Mockito.spy(LibvirtComputingResource.class);
private final static long HYPERVISOR_LIBVIRT_VERSION_SUPPORTS_IOURING = 6003000; private final static long HYPERVISOR_LIBVIRT_VERSION_SUPPORTS_IOURING = 6003000;
private final static long HYPERVISOR_QEMU_VERSION_SUPPORTS_IOURING = 5000000; private final static long HYPERVISOR_QEMU_VERSION_SUPPORTS_IOURING = 5000000;
@ -217,6 +236,7 @@ public class LibvirtComputingResourceTest {
@Before @Before
public void setup() throws Exception { public void setup() throws Exception {
libvirtComputingResourceSpy._qemuSocketsPath = new File("/var/run/qemu");
Scanner scanner = new Scanner(memInfo); Scanner scanner = new Scanner(memInfo);
PowerMockito.whenNew(Scanner.class).withAnyArguments().thenReturn(scanner); PowerMockito.whenNew(Scanner.class).withAnyArguments().thenReturn(scanner);
} }
@ -243,15 +263,13 @@ public class LibvirtComputingResourceTest {
final String vncAddr = ""; final String vncAddr = "";
final String vncPassword = "mySuperSecretPassword"; final String vncPassword = "mySuperSecretPassword";
final LibvirtComputingResource lcr = new LibvirtComputingResource();
lcr._qemuSocketsPath = new File("/var/run/qemu");
final VirtualMachineTO to = new VirtualMachineTO(id, name, VirtualMachine.Type.User, cpus, speed, minRam, maxRam, BootloaderType.HVM, os, false, false, vncPassword); final VirtualMachineTO to = new VirtualMachineTO(id, name, VirtualMachine.Type.User, cpus, speed, minRam, maxRam, BootloaderType.HVM, os, false, false, vncPassword);
to.setVncAddr(vncAddr); to.setVncAddr(vncAddr);
to.setArch("x86_64"); to.setArch("x86_64");
to.setUuid("b0f0a72d-7efb-3cad-a8ff-70ebf30b3af9"); to.setUuid("b0f0a72d-7efb-3cad-a8ff-70ebf30b3af9");
to.setVcpuMaxLimit(cpus + 1);
final LibvirtVMDef vm = lcr.createVMFromSpec(to); final LibvirtVMDef vm = libvirtComputingResourceSpy.createVMFromSpec(to);
vm.setHvsType(hyperVisorType); vm.setHvsType(hyperVisorType);
verifyVm(to, vm); verifyVm(to, vm);
@ -276,15 +294,13 @@ public class LibvirtComputingResourceTest {
final String vncAddr = ""; final String vncAddr = "";
final String vncPassword = "mySuperSecretPassword"; final String vncPassword = "mySuperSecretPassword";
final LibvirtComputingResource lcr = new LibvirtComputingResource();
lcr._qemuSocketsPath = new File("/var/run/qemu");
final VirtualMachineTO to = new VirtualMachineTO(id, name, VirtualMachine.Type.User, cpus, minSpeed, maxSpeed, minRam, maxRam, BootloaderType.HVM, os, false, false, vncPassword); final VirtualMachineTO to = new VirtualMachineTO(id, name, VirtualMachine.Type.User, cpus, minSpeed, maxSpeed, minRam, maxRam, BootloaderType.HVM, os, false, false, vncPassword);
to.setVncAddr(vncAddr); to.setVncAddr(vncAddr);
to.setArch("x86_64"); to.setArch("x86_64");
to.setUuid("b0f0a72d-7efb-3cad-a8ff-70ebf30b3af9"); to.setUuid("b0f0a72d-7efb-3cad-a8ff-70ebf30b3af9");
to.setVcpuMaxLimit(cpus + 1);
final LibvirtVMDef vm = lcr.createVMFromSpec(to); final LibvirtVMDef vm = libvirtComputingResourceSpy.createVMFromSpec(to);
vm.setHvsType(hyperVisorType); vm.setHvsType(hyperVisorType);
verifyVm(to, vm); verifyVm(to, vm);
@ -309,14 +325,11 @@ public class LibvirtComputingResourceTest {
final String vncAddr = ""; final String vncAddr = "";
final String vncPassword = "mySuperSecretPassword"; final String vncPassword = "mySuperSecretPassword";
final LibvirtComputingResource lcr = new LibvirtComputingResource();
lcr._qemuSocketsPath = new File("/var/run/qemu");
final VirtualMachineTO to = new VirtualMachineTO(id, name, VirtualMachine.Type.User, cpus, minSpeed, maxSpeed, minRam, maxRam, BootloaderType.HVM, os, false, false, vncPassword); final VirtualMachineTO to = new VirtualMachineTO(id, name, VirtualMachine.Type.User, cpus, minSpeed, maxSpeed, minRam, maxRam, BootloaderType.HVM, os, false, false, vncPassword);
to.setVncAddr(vncAddr); to.setVncAddr(vncAddr);
to.setUuid("b0f0a72d-7efb-3cad-a8ff-70ebf30b3af9"); to.setUuid("b0f0a72d-7efb-3cad-a8ff-70ebf30b3af9");
final LibvirtVMDef vm = lcr.createVMFromSpec(to); LibvirtVMDef vm = libvirtComputingResourceSpy.createVMFromSpec(to);
vm.setHvsType(hyperVisorType); vm.setHvsType(hyperVisorType);
verifyVm(to, vm); verifyVm(to, vm);
@ -331,59 +344,388 @@ public class LibvirtComputingResourceTest {
*/ */
@Test @Test
public void testCreateVMFromSpec() { public void testCreateVMFromSpec() {
final int id = random.nextInt(65534); VirtualMachineTO to = createDefaultVM(false);
final String name = "test-instance-1"; final LibvirtVMDef vm = libvirtComputingResourceSpy.createVMFromSpec(to);
final int cpus = random.nextInt(2) + 1;
final int minSpeed = 1024;
final int maxSpeed = 2048;
final int minRam = 256 * 1024;
final int maxRam = 512 * 1024;
final String os = "Ubuntu";
final String vncAddr = "";
final String vncPassword = "mySuperSecretPassword";
final LibvirtComputingResource lcr = new LibvirtComputingResource();
lcr._qemuSocketsPath = new File("/var/run/qemu");
final VirtualMachineTO to =
new VirtualMachineTO(id, name, VirtualMachine.Type.User, cpus, minSpeed, maxSpeed, minRam, maxRam, BootloaderType.HVM, os, false, false, vncPassword);
to.setVncAddr(vncAddr);
to.setArch("x86_64");
to.setUuid("b0f0a72d-7efb-3cad-a8ff-70ebf30b3af9");
final LibvirtVMDef vm = lcr.createVMFromSpec(to);
vm.setHvsType(hyperVisorType); vm.setHvsType(hyperVisorType);
verifyVm(to, vm); verifyVm(to, vm);
} }
private void verifyVm(final VirtualMachineTO to, final LibvirtVMDef vm) { @Test
final Document domainDoc = parse(vm.toString()); public void testCreateGuestFromSpecWithoutCustomParam() {
assertXpath(domainDoc, "/domain/@type", vm.getHvsType()); VirtualMachineTO to = createDefaultVM(false);
assertXpath(domainDoc, "/domain/name/text()", to.getName()); LibvirtVMDef vm = new LibvirtVMDef();
assertXpath(domainDoc, "/domain/uuid/text()", to.getUuid()); GuestDef guestDef = libvirtComputingResourceSpy.createGuestFromSpec(to, vm, to.getUuid(), null);
assertXpath(domainDoc, "/domain/description/text()", to.getOs()); verifySysInfo(guestDef, "smbios", to.getUuid(), "pc");
assertXpath(domainDoc, "/domain/clock/@offset", "utc"); Assert.assertEquals(GuestDef.BootType.BIOS, guestDef.getBootType());
assertNodeExists(domainDoc, "/domain/features/pae"); Assert.assertNull(guestDef.getBootMode());
assertNodeExists(domainDoc, "/domain/features/apic"); }
assertNodeExists(domainDoc, "/domain/features/acpi");
assertXpath(domainDoc, "/domain/devices/serial/@type", "pty");
assertXpath(domainDoc, "/domain/devices/serial/target/@port", "0");
assertXpath(domainDoc, "/domain/devices/graphics/@type", "vnc");
assertXpath(domainDoc, "/domain/devices/graphics/@listen", to.getVncAddr());
assertXpath(domainDoc, "/domain/devices/graphics/@autoport", "yes");
assertXpath(domainDoc, "/domain/devices/graphics/@passwd", to.getVncPassword());
assertXpath(domainDoc, "/domain/devices/console/@type", "pty"); @Test
assertXpath(domainDoc, "/domain/devices/console/target/@port", "0"); public void testCreateGuestFromSpecWithCustomParamAndUefi() {
assertXpath(domainDoc, "/domain/devices/input/@type", "tablet"); VirtualMachineTO to = createDefaultVM(false);
assertXpath(domainDoc, "/domain/devices/input/@bus", "usb");
assertNodeExists(domainDoc, "/domain/devices/channel"); Map<String, String> extraConfig = new HashMap<>();
assertXpath(domainDoc, "/domain/devices/channel/@type", ChannelDef.ChannelType.UNIX.toString()); extraConfig.put(GuestDef.BootType.UEFI.toString(), "legacy");
LibvirtVMDef vm = new LibvirtVMDef();
GuestDef guestDef = libvirtComputingResourceSpy.createGuestFromSpec(to, vm, to.getUuid(), extraConfig);
verifySysInfo(guestDef, "smbios", to.getUuid(), "q35");
Assert.assertEquals(GuestDef.BootType.UEFI, guestDef.getBootType());
Assert.assertEquals(GuestDef.BootMode.LEGACY, guestDef.getBootMode());
}
@Test
public void testCreateGuestFromSpecWithCustomParamUefiAndSecure() {
VirtualMachineTO to = createDefaultVM(false);
Map<String, String> extraConfig = new HashMap<>();
extraConfig.put(GuestDef.BootType.UEFI.toString(), "secure");
LibvirtVMDef vm = new LibvirtVMDef();
GuestDef guestDef = libvirtComputingResourceSpy.createGuestFromSpec(to, vm, to.getUuid(), extraConfig);
verifySysInfo(guestDef, "smbios", to.getUuid(), "q35");
Assert.assertEquals(GuestDef.BootType.UEFI, guestDef.getBootType());
Assert.assertEquals(GuestDef.BootMode.SECURE, guestDef.getBootMode());
}
@Test
public void testCreateGuestResourceDef() {
VirtualMachineTO to = createDefaultVM(false);
GuestResourceDef guestResourceDef = libvirtComputingResourceSpy.createGuestResourceDef(to);
verifyGuestResourceDef(guestResourceDef, to);
}
@Test
public void testCreateDevicesDef() {
VirtualMachineTO to = createDefaultVM(false);
GuestDef guest = new GuestDef();
guest.setGuestType(GuestType.KVM);
DevicesDef devicesDef = libvirtComputingResourceSpy.createDevicesDef(to, guest, to.getCpus() + 1, false);
verifyDevices(devicesDef, to);
}
@Test
public void testCreateDevicesWithSCSIDisk() {
VirtualMachineTO to = createDefaultVM(false);
to.setDetails(new HashMap<>());
libvirtComputingResourceSpy._guestCpuArch = "aarch64";
GuestDef guest = new GuestDef();
guest.setGuestType(GuestType.KVM);
DevicesDef devicesDef = libvirtComputingResourceSpy.createDevicesDef(to, guest, to.getCpus() + 1, false);
verifyDevices(devicesDef, to);
Document domainDoc = parse(devicesDef.toString());
assertNodeExists(domainDoc, "/devices/controller[@type='scsi']");
assertNodeExists(domainDoc, "/devices/controller[@model='virtio-scsi']");
assertNodeExists(domainDoc, "/devices/controller/address[@type='pci']");
assertNodeExists(domainDoc, "/devices/controller/driver[@queues='" + (to.getCpus() + 1) + "']");
}
@Test
public void testConfigureGuestAndSystemVMToUseKVM() {
VirtualMachineTO to = createDefaultVM(false);
libvirtComputingResourceSpy._hypervisorLibvirtVersion = 100;
libvirtComputingResourceSpy._hypervisorQemuVersion = 10;
LibvirtVMDef vm = new LibvirtVMDef();
GuestDef guestFromSpec = libvirtComputingResourceSpy.createGuestFromSpec(to, vm, to.getUuid(), null);
Assert.assertEquals(GuestDef.GuestType.KVM, guestFromSpec.getGuestType());
Assert.assertEquals(HypervisorType.KVM.toString().toLowerCase(), vm.getHvsType());
}
@Test
public void testConfigureGuestAndUserVMToUseLXC() {
VirtualMachineTO to = createDefaultVM(false);
libvirtComputingResourceSpy._hypervisorType = HypervisorType.LXC;
LibvirtVMDef vm = new LibvirtVMDef();
GuestDef guestFromSpec = libvirtComputingResourceSpy.createGuestFromSpec(to, vm, to.getUuid(), null);
Assert.assertEquals(GuestDef.GuestType.LXC, guestFromSpec.getGuestType());
Assert.assertEquals(HypervisorType.LXC.toString().toLowerCase(), vm.getHvsType());
}
@Test
public void testCreateCpuTuneDefWithoutQuotaAndPeriod() {
VirtualMachineTO to = createDefaultVM(false);
CpuTuneDef cpuTuneDef = libvirtComputingResourceSpy.createCpuTuneDef(to);
Document domainDoc = parse(cpuTuneDef.toString());
assertXpath(domainDoc, "/cputune/shares/text()", String.valueOf(cpuTuneDef.getShares()));
}
@Test
public void testCreateCpuTuneDefWithQuotaAndPeriod() {
VirtualMachineTO to = createDefaultVM(true);
to.setCpuQuotaPercentage(10.0);
CpuTuneDef cpuTuneDef = libvirtComputingResourceSpy.createCpuTuneDef(to);
Document domainDoc = parse(cpuTuneDef.toString());
assertXpath(domainDoc, "/cputune/shares/text()", String.valueOf(cpuTuneDef.getShares()));
assertXpath(domainDoc, "/cputune/quota/text()", String.valueOf(cpuTuneDef.getQuota()));
assertXpath(domainDoc, "/cputune/period/text()", String.valueOf(cpuTuneDef.getPeriod()));
}
@Test
public void testCreateCpuTuneDefWithMinQuota() {
VirtualMachineTO to = createDefaultVM(true);
to.setCpuQuotaPercentage(0.01);
CpuTuneDef cpuTuneDef = libvirtComputingResourceSpy.createCpuTuneDef(to);
Document domainDoc = parse(cpuTuneDef.toString());
assertXpath(domainDoc, "/cputune/shares/text()", String.valueOf(cpuTuneDef.getShares()));
assertXpath(domainDoc, "/cputune/quota/text()", "1000");
assertXpath(domainDoc, "/cputune/period/text()", String.valueOf(cpuTuneDef.getPeriod()));
}
@Test
public void testCreateDefaultClockDef() {
VirtualMachineTO to = createDefaultVM(false);
ClockDef clockDef = libvirtComputingResourceSpy.createClockDef(to);
Document domainDoc = parse(clockDef.toString());
assertXpath(domainDoc, "/clock/@offset", "utc");
}
@Test
public void testCreateClockDefWindows() {
VirtualMachineTO to = createDefaultVM(false);
to.setOs("Windows");
ClockDef clockDef = libvirtComputingResourceSpy.createClockDef(to);
Document domainDoc = parse(clockDef.toString());
assertXpath(domainDoc, "/clock/@offset", "localtime");
assertXpath(domainDoc, "/clock/timer/@name", "hypervclock");
assertXpath(domainDoc, "/clock/timer/@present", "yes");
}
@Test
public void testCreateClockDefKvmclock() {
VirtualMachineTO to = createDefaultVM(false);
libvirtComputingResourceSpy._hypervisorLibvirtVersion = 9020;
ClockDef clockDef = libvirtComputingResourceSpy.createClockDef(to);
Document domainDoc = parse(clockDef.toString());
assertXpath(domainDoc, "/clock/@offset", "utc");
assertXpath(domainDoc, "/clock/timer/@name", "kvmclock");
}
@Test
public void testCreateTermPolicy() {
TermPolicy termPolicy = libvirtComputingResourceSpy.createTermPolicy();
String xml = "<terms>\n" + termPolicy.toString() + "</terms>";
Document domainDoc = parse(xml);
assertXpath(domainDoc, "/terms/on_reboot/text()", "restart");
assertXpath(domainDoc, "/terms/on_poweroff/text()", "destroy");
assertXpath(domainDoc, "/terms/on_crash/text()", "destroy");
}
@Test
public void testCreateFeaturesDef() {
VirtualMachineTO to = createDefaultVM(false);
FeaturesDef featuresDef = libvirtComputingResourceSpy.createFeaturesDef(null, false, false);
String xml = "<domain>" + featuresDef.toString() + "</domain>";
Document domainDoc = parse(xml);
verifyFeatures(domainDoc);
}
@Test
public void testCreateFeaturesDefWithUefi() {
VirtualMachineTO to = createDefaultVM(false);
HashMap<String, String> extraConfig = new HashMap<>();
extraConfig.put(GuestDef.BootType.UEFI.toString(), "");
FeaturesDef featuresDef = libvirtComputingResourceSpy.createFeaturesDef(extraConfig, true, true);
String xml = "<domain>" + featuresDef.toString() + "</domain>";
Document domainDoc = parse(xml);
verifyFeatures(domainDoc);
}
@Test
public void testCreateWatchDog() {
WatchDogDef watchDogDef = libvirtComputingResourceSpy.createWatchDogDef();
verifyWatchDogDevices(parse(watchDogDef.toString()), "");
}
@Test
public void testCreateArm64UsbDef() {
DevicesDef devicesDef = new DevicesDef();
libvirtComputingResourceSpy.createArm64UsbDef(devicesDef);
Document domainDoc = parse(devicesDef.toString());
assertXpath(domainDoc, "/devices/controller/@type", "usb");
assertXpath(domainDoc, "/devices/controller/@model", "qemu-xhci");
assertXpath(domainDoc, "/devices/controller/address/@type", "pci");
assertNodeExists(domainDoc, "/devices/input[@type='keyboard']");
assertNodeExists(domainDoc, "/devices/input[@bus='usb']");
assertNodeExists(domainDoc, "/devices/input[@type='mouse']");
assertNodeExists(domainDoc, "/devices/input[@bus='usb']");
}
@Test
public void testCreateInputDef() {
InputDef inputDef = libvirtComputingResourceSpy.createTabletInputDef();
verifyTabletInputDevice(parse(inputDef.toString()), "");
}
@Test
public void testCreateGraphicDef() {
VirtualMachineTO to = createDefaultVM(false);
GraphicDef graphicDef = libvirtComputingResourceSpy.createGraphicDef(to);
verifyGraphicsDevices(to, parse(graphicDef.toString()), "");
}
@Test
public void testCreateChannelDef() {
VirtualMachineTO to = createDefaultVM(false);
ChannelDef channelDef = libvirtComputingResourceSpy.createChannelDef(to);
verifyChannelDevices(to, parse(channelDef.toString()), "");
}
@Test
public void testCreateSCSIDef() {
VirtualMachineTO to = createDefaultVM(false);
SCSIDef scsiDef = libvirtComputingResourceSpy.createSCSIDef(to.getCpus());
Document domainDoc = parse(scsiDef.toString());
verifyScsi(to, domainDoc, "");
}
@Test
public void testCreateConsoleDef() {
VirtualMachineTO to = createDefaultVM(false);
ConsoleDef consoleDef = libvirtComputingResourceSpy.createConsoleDef();
verifyConsoleDevices(parse(consoleDef.toString()), "");
}
@Test
public void testCreateVideoDef() {
VirtualMachineTO to = createDefaultVM(false);
libvirtComputingResourceSpy._videoRam = 200;
libvirtComputingResourceSpy._videoHw = "vGPU";
VideoDef videoDef = libvirtComputingResourceSpy.createVideoDef();
Document domainDoc = parse(videoDef.toString());
assertXpath(domainDoc, "/video/model/@type", "vGPU");
assertXpath(domainDoc, "/video/model/@vram", "200");
}
@Test
public void testCreateRngDef() {
VirtualMachineTO to = createDefaultVM(false);
RngDef rngDef = libvirtComputingResourceSpy.createRngDef();
Document domainDoc = parse(rngDef.toString());
assertXpath(domainDoc, "/rng/@model", "virtio");
assertXpath(domainDoc, "/rng/rate/@period", "1000");
assertXpath(domainDoc, "/rng/rate/@bytes", "2048");
assertXpath(domainDoc, "/rng/backend/@model", "random");
assertXpath(domainDoc, "/rng/backend/text()", "/dev/random");
}
@Test
public void testCreateSerialDef() {
VirtualMachineTO to = createDefaultVM(false);
SerialDef serialDef = libvirtComputingResourceSpy.createSerialDef();
verifySerialDevices(parse(serialDef.toString()), "");
}
private VirtualMachineTO createDefaultVM(boolean limitCpuUse) {
int id = random.nextInt(65534);
String name = "test-instance-1";
int cpus = random.nextInt(2) + 1;
int minSpeed = 1024;
int maxSpeed = 2048;
int minRam = 256 * 1024;
int maxRam = 512 * 1024;
String os = "Ubuntu";
String vncAddr = "";
String vncPassword = "mySuperSecretPassword";
final VirtualMachineTO to = new VirtualMachineTO(id, name, VirtualMachine.Type.User, cpus, minSpeed, maxSpeed, minRam, maxRam, BootloaderType.HVM, os, false, limitCpuUse,
vncPassword);
to.setArch("x86_64");
to.setVncAddr(vncAddr);
to.setUuid("b0f0a72d-7efb-3cad-a8ff-70ebf30b3af9");
to.setVcpuMaxLimit(cpus + 1);
return to;
}
private void verifyGuestResourceDef(GuestResourceDef guestResourceDef, VirtualMachineTO to) {
String xml = "<domain>" + guestResourceDef.toString() + "</domain>";
Document domainDoc = parse(xml);
String minRam = String.valueOf(to.getMinRam() / 1024);
verifyMemory(to, domainDoc, minRam);
assertNodeExists(domainDoc, "/domain/vcpu");
verifyMemballoonDevices(domainDoc);
verifyVcpu(to, domainDoc);
}
private void verifyVm(VirtualMachineTO to, LibvirtVMDef vm) {
Document domainDoc = parse(vm.toString());
verifyHeader(domainDoc, vm.getHvsType(), to.getName(), to.getUuid(), to.getOs());
verifyFeatures(domainDoc);
verifyClock(domainDoc);
verifySerialDevices(domainDoc, "/domain/devices");
verifyGraphicsDevices(to, domainDoc, "/domain/devices");
verifyConsoleDevices(domainDoc, "/domain/devices");
verifyTabletInputDevice(domainDoc, "/domain/devices");
verifyChannelDevices(to, domainDoc, "/domain/devices");
String minRam = String.valueOf(to.getMinRam() / 1024);
verifyMemory(to, domainDoc, minRam);
assertNodeExists(domainDoc, "/domain/cpu");
verifyMemballoonDevices(domainDoc);
verifyVcpu(to, domainDoc);
verifyOsType(domainDoc);
verifyOsBoot(domainDoc);
verifyPoliticOn_(domainDoc);
verifyWatchDogDevices(domainDoc, "/domain/devices");
}
private void verifyMemballoonDevices(Document domainDoc) {
assertXpath(domainDoc, "/domain/devices/memballoon/@model", "virtio");
}
private void verifyVcpu(VirtualMachineTO to, Document domainDoc) {
assertXpath(domainDoc, "/domain/vcpu/text()", String.valueOf(to.getCpus()));
}
private void verifyMemory(VirtualMachineTO to, Document domainDoc, String minRam) {
assertXpath(domainDoc, "/domain/memory/text()", String.valueOf(to.getMaxRam() / 1024));
assertXpath(domainDoc, "/domain/currentMemory/text()", minRam);
}
private void verifyWatchDogDevices(Document domainDoc, String prefix) {
assertXpath(domainDoc, prefix + "/watchdog/@model", "i6300esb");
assertXpath(domainDoc, prefix + "/watchdog/@action", "none");
}
private void verifyChannelDevices(VirtualMachineTO to, Document domainDoc, String prefix) {
assertNodeExists(domainDoc, prefix + "/channel");
assertXpath(domainDoc, prefix + "/channel/@type", ChannelDef.ChannelType.UNIX.toString());
/* /*
The configure() method of LibvirtComputingResource has not been called, so the default path for the sockets The configure() method of LibvirtComputingResource has not been called, so the default path for the sockets
@ -392,28 +734,93 @@ public class LibvirtComputingResourceTest {
Calling configure is also not possible since that looks for certain files on the system which are not present Calling configure is also not possible since that looks for certain files on the system which are not present
during testing during testing
*/ */
assertXpath(domainDoc, "/domain/devices/channel/source/@path", "/var/run/qemu/" + to.getName() + ".org.qemu.guest_agent.0"); assertXpath(domainDoc, prefix + "/channel/source/@path", "/var/run/qemu/" + to.getName() + ".org.qemu.guest_agent.0");
assertXpath(domainDoc, "/domain/devices/channel/target/@name", "org.qemu.guest_agent.0"); assertXpath(domainDoc, prefix + "/channel/target/@name", "org.qemu.guest_agent.0");
}
assertXpath(domainDoc, "/domain/memory/text()", String.valueOf( to.getMaxRam() / 1024 )); private void verifyTabletInputDevice(Document domainDoc, String prefix) {
assertXpath(domainDoc, "/domain/currentMemory/text()", String.valueOf( to.getMinRam() / 1024 )); assertXpath(domainDoc, prefix + "/input/@type", "tablet");
assertXpath(domainDoc, prefix + "/input/@bus", "usb");
}
assertXpath(domainDoc, "/domain/devices/memballoon/@model", "virtio"); private void verifyConsoleDevices(Document domainDoc, String prefix) {
assertXpath(domainDoc, "/domain/vcpu/text()", String.valueOf(to.getCpus())); assertXpath(domainDoc, prefix + "/console/@type", "pty");
assertXpath(domainDoc, prefix + "/console/target/@port", "0");
}
assertXpath(domainDoc, "/domain/os/type/@machine", "pc"); private void verifyScsi(VirtualMachineTO to, Document domainDoc, String prefix) {
assertXpath(domainDoc, "/domain/os/type/text()", "hvm"); assertXpath(domainDoc, prefix + "/controller/@type", "scsi");
assertXpath(domainDoc, prefix + "/controller/@model", "virtio-scsi");
assertXpath(domainDoc, prefix + "/controller/address/@type", "pci");
assertXpath(domainDoc, prefix + "/controller/driver/@queues", String.valueOf(to.getCpus()));
}
assertNodeExists(domainDoc, "/domain/cpu"); private void verifyClock(Document domainDoc) {
assertXpath(domainDoc, "/domain/clock/@offset", "utc");
}
private void verifyGraphicsDevices(VirtualMachineTO to, Document domainDoc, String prefix) {
assertXpath(domainDoc, prefix + "/graphics/@type", "vnc");
assertXpath(domainDoc, prefix + "/graphics/@listen", to.getVncAddr());
assertXpath(domainDoc, prefix + "/graphics/@autoport", "yes");
assertXpath(domainDoc, prefix + "/graphics/@passwd", to.getVncPassword());
}
private void verifySerialDevices(Document domainDoc, String prefix) {
assertXpath(domainDoc, prefix + "/serial/@type", "pty");
assertXpath(domainDoc, prefix + "/serial/target/@port", "0");
}
private void verifyOsBoot(Document domainDoc) {
assertNodeExists(domainDoc, "/domain/os/boot[@dev='cdrom']"); assertNodeExists(domainDoc, "/domain/os/boot[@dev='cdrom']");
assertNodeExists(domainDoc, "/domain/os/boot[@dev='hd']"); assertNodeExists(domainDoc, "/domain/os/boot[@dev='hd']");
}
private void verifyOsType(Document domainDoc) {
assertXpath(domainDoc, "/domain/os/type/@machine", "pc");
assertXpath(domainDoc, "/domain/os/type/text()", "hvm");
}
private void verifyPoliticOn_(Document domainDoc) {
assertXpath(domainDoc, "/domain/on_reboot/text()", "restart"); assertXpath(domainDoc, "/domain/on_reboot/text()", "restart");
assertXpath(domainDoc, "/domain/on_poweroff/text()", "destroy"); assertXpath(domainDoc, "/domain/on_poweroff/text()", "destroy");
assertXpath(domainDoc, "/domain/on_crash/text()", "destroy"); assertXpath(domainDoc, "/domain/on_crash/text()", "destroy");
}
assertXpath(domainDoc, "/domain/devices/watchdog/@model", "i6300esb"); private void verifyFeatures(Document domainDoc) {
assertXpath(domainDoc, "/domain/devices/watchdog/@action", "none"); assertNodeExists(domainDoc, "/domain/features/pae");
assertNodeExists(domainDoc, "/domain/features/apic");
assertNodeExists(domainDoc, "/domain/features/acpi");
}
private void verifyHeader(Document domainDoc, String hvsType, String name, String uuid, String os) {
assertXpath(domainDoc, "/domain/@type", hvsType);
assertXpath(domainDoc, "/domain/name/text()", name);
assertXpath(domainDoc, "/domain/uuid/text()", uuid);
assertXpath(domainDoc, "/domain/description/text()", os);
}
private void verifyDevices(DevicesDef devicesDef, VirtualMachineTO to) {
Document domainDoc = parse(devicesDef.toString());
verifyWatchDogDevices(domainDoc, "/devices");
verifyConsoleDevices(domainDoc, "/devices");
verifySerialDevices(domainDoc, "/devices");
verifyGraphicsDevices(to, domainDoc, "/devices");
verifyChannelDevices(to, domainDoc, "/devices");
verifyTabletInputDevice(domainDoc, "/devices");
}
private void verifySysInfo(GuestDef guestDef, String type, String uuid, String machine) {
// Need put <guestdef> because the string of guestdef generate two root element in XML, raising a error in parse.
String xml = "<guestdef>\n" + guestDef.toString() + "</guestdef>";
Document domainDoc = parse(xml);
assertXpath(domainDoc, "/guestdef/sysinfo/@type", type);
assertNodeExists(domainDoc, "/guestdef/sysinfo/system/entry[@name='manufacturer']");
assertNodeExists(domainDoc, "/guestdef/sysinfo/system/entry[@name='product']");
assertXpath(domainDoc, "/guestdef/sysinfo/system/entry[@name='uuid']/text()", uuid);
assertXpath(domainDoc, "/guestdef/os/type/@machine", machine);
} }
static Document parse(final String input) { static Document parse(final String input) {