orchestration,hypervisor: allow custom manufacture, product for vm (#9163)

Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
This commit is contained in:
Abhishek Kumar 2024-08-22 20:49:04 +05:30 committed by GitHub
parent b215abc30a
commit 1e12a80210
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 149 additions and 24 deletions

View File

@ -84,6 +84,8 @@ public class VirtualMachineTO {
Map<String, String> extraConfig = new HashMap<>(); Map<String, String> extraConfig = new HashMap<>();
Map<Long, String> networkIdToNetworkNameMap = new HashMap<>(); Map<Long, String> networkIdToNetworkNameMap = new HashMap<>();
DeployAsIsInfoTO deployAsIsInfo; DeployAsIsInfoTO deployAsIsInfo;
String metadataManufacturer;
String metadataProductName;
public VirtualMachineTO(long id, String instanceName, VirtualMachine.Type type, int cpus, Integer speed, long minRam, long maxRam, BootloaderType bootloader, public VirtualMachineTO(long id, String instanceName, VirtualMachine.Type type, int cpus, Integer speed, long minRam, long maxRam, BootloaderType bootloader,
String os, boolean enableHA, boolean limitCpuUse, String vncPassword) { String os, boolean enableHA, boolean limitCpuUse, String vncPassword) {
@ -429,6 +431,22 @@ public class VirtualMachineTO {
this.deployAsIsInfo = deployAsIsInfo; this.deployAsIsInfo = deployAsIsInfo;
} }
public String getMetadataManufacturer() {
return metadataManufacturer;
}
public void setMetadataManufacturer(String metadataManufacturer) {
this.metadataManufacturer = metadataManufacturer;
}
public String getMetadataProductName() {
return metadataProductName;
}
public void setMetadataProductName(String metadataProductName) {
this.metadataProductName = metadataProductName;
}
@Override @Override
public String toString() { public String toString() {
return String.format("VM {id: \"%s\", name: \"%s\", uuid: \"%s\", type: \"%s\"}", id, name, uuid, type); return String.format("VM {id: \"%s\", name: \"%s\", uuid: \"%s\", type: \"%s\"}", id, name, uuid, type);

View File

@ -87,6 +87,20 @@ public interface VirtualMachineManager extends Manager {
ConfigKey<String> MetadataCustomCloudName = new ConfigKey<>("Advanced", String.class, "metadata.custom.cloud.name", "", ConfigKey<String> MetadataCustomCloudName = new ConfigKey<>("Advanced", String.class, "metadata.custom.cloud.name", "",
"If provided, a custom cloud-name in cloud-init metadata", true, ConfigKey.Scope.Zone); "If provided, a custom cloud-name in cloud-init metadata", true, ConfigKey.Scope.Zone);
ConfigKey<String> VmMetadataManufacturer = new ConfigKey<>("Advanced", String.class,
"vm.metadata.manufacturer", "Apache Software Foundation",
"If provided, a custom manufacturer will be used in the instance metadata. When an empty" +
"value is set then default manufacturer will be 'Apache Software Foundation'. " +
"A custom manufacturer may break cloud-init functionality with CloudStack datasource. Please " +
"refer documentation", true, ConfigKey.Scope.Zone);
ConfigKey<String> VmMetadataProductName = new ConfigKey<>("Advanced", String.class,
"vm.metadata.product", "",
"If provided, a custom product name will be used in the instance metadata. When an empty" +
"value is set then default product name will be 'CloudStack <HYPERVISIOR_NAME> Hypervisor'. " +
"A custom product name may break cloud-init functionality with CloudStack datasource. Please " +
"refer documentation",
true, ConfigKey.Scope.Zone);
interface Topics { interface Topics {
String VM_POWER_STATE = "vm.powerstate"; String VM_POWER_STATE = "vm.powerstate";
} }

View File

@ -49,15 +49,6 @@ import javax.inject.Inject;
import javax.naming.ConfigurationException; import javax.naming.ConfigurationException;
import javax.persistence.EntityExistsException; import javax.persistence.EntityExistsException;
import com.cloud.configuration.Resource;
import com.cloud.domain.Domain;
import com.cloud.domain.dao.DomainDao;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.network.vpc.VpcVO;
import com.cloud.network.vpc.dao.VpcDao;
import com.cloud.user.dao.AccountDao;
import com.cloud.event.ActionEventUtils;
import com.google.gson.Gson;
import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao; import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao;
import org.apache.cloudstack.annotation.AnnotationService; import org.apache.cloudstack.annotation.AnnotationService;
import org.apache.cloudstack.annotation.dao.AnnotationDao; import org.apache.cloudstack.annotation.dao.AnnotationDao;
@ -160,6 +151,7 @@ import com.cloud.api.query.dao.UserVmJoinDao;
import com.cloud.api.query.vo.DomainRouterJoinVO; import com.cloud.api.query.vo.DomainRouterJoinVO;
import com.cloud.api.query.vo.UserVmJoinVO; import com.cloud.api.query.vo.UserVmJoinVO;
import com.cloud.capacity.CapacityManager; import com.cloud.capacity.CapacityManager;
import com.cloud.configuration.Resource;
import com.cloud.dc.ClusterDetailsDao; import com.cloud.dc.ClusterDetailsDao;
import com.cloud.dc.ClusterDetailsVO; import com.cloud.dc.ClusterDetailsVO;
import com.cloud.dc.ClusterVO; import com.cloud.dc.ClusterVO;
@ -178,6 +170,9 @@ import com.cloud.deploy.DeploymentPlanner.ExcludeList;
import com.cloud.deploy.DeploymentPlanningManager; import com.cloud.deploy.DeploymentPlanningManager;
import com.cloud.deploy.DeploymentPlanningManagerImpl; import com.cloud.deploy.DeploymentPlanningManagerImpl;
import com.cloud.deployasis.dao.UserVmDeployAsIsDetailsDao; import com.cloud.deployasis.dao.UserVmDeployAsIsDetailsDao;
import com.cloud.domain.Domain;
import com.cloud.domain.dao.DomainDao;
import com.cloud.event.ActionEventUtils;
import com.cloud.event.EventTypes; import com.cloud.event.EventTypes;
import com.cloud.event.UsageEventUtils; import com.cloud.event.UsageEventUtils;
import com.cloud.event.UsageEventVO; import com.cloud.event.UsageEventVO;
@ -189,6 +184,7 @@ import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.InsufficientServerCapacityException; import com.cloud.exception.InsufficientServerCapacityException;
import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.OperationTimedoutException; import com.cloud.exception.OperationTimedoutException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException; import com.cloud.exception.ResourceUnavailableException;
import com.cloud.exception.StorageAccessException; import com.cloud.exception.StorageAccessException;
import com.cloud.exception.StorageUnavailableException; import com.cloud.exception.StorageUnavailableException;
@ -211,6 +207,8 @@ import com.cloud.network.dao.NetworkDetailsDao;
import com.cloud.network.dao.NetworkVO; import com.cloud.network.dao.NetworkVO;
import com.cloud.network.router.VirtualRouter; import com.cloud.network.router.VirtualRouter;
import com.cloud.network.security.SecurityGroupManager; import com.cloud.network.security.SecurityGroupManager;
import com.cloud.network.vpc.VpcVO;
import com.cloud.network.vpc.dao.VpcDao;
import com.cloud.offering.DiskOffering; import com.cloud.offering.DiskOffering;
import com.cloud.offering.DiskOfferingInfo; import com.cloud.offering.DiskOfferingInfo;
import com.cloud.offering.NetworkOffering; import com.cloud.offering.NetworkOffering;
@ -246,6 +244,7 @@ import com.cloud.template.VirtualMachineTemplate;
import com.cloud.user.Account; import com.cloud.user.Account;
import com.cloud.user.ResourceLimitService; import com.cloud.user.ResourceLimitService;
import com.cloud.user.User; import com.cloud.user.User;
import com.cloud.user.dao.AccountDao;
import com.cloud.uservm.UserVm; import com.cloud.uservm.UserVm;
import com.cloud.utils.DateUtil; import com.cloud.utils.DateUtil;
import com.cloud.utils.Journal; import com.cloud.utils.Journal;
@ -281,6 +280,7 @@ import com.cloud.vm.dao.VMInstanceDao;
import com.cloud.vm.snapshot.VMSnapshotManager; import com.cloud.vm.snapshot.VMSnapshotManager;
import com.cloud.vm.snapshot.VMSnapshotVO; import com.cloud.vm.snapshot.VMSnapshotVO;
import com.cloud.vm.snapshot.dao.VMSnapshotDao; import com.cloud.vm.snapshot.dao.VMSnapshotDao;
import com.google.gson.Gson;
public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMachineManager, VmWorkJobHandler, Listener, Configurable { public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMachineManager, VmWorkJobHandler, Listener, Configurable {
@ -1101,6 +1101,19 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
markVolumesInPool(vm, answer); markVolumesInPool(vm, answer);
} }
protected void updateVmMetadataManufacturerAndProduct(VirtualMachineTO vmTO, VMInstanceVO vm) {
String metadataManufacturer = VmMetadataManufacturer.valueIn(vm.getDataCenterId());
if (StringUtils.isBlank(metadataManufacturer)) {
metadataManufacturer = VmMetadataManufacturer.defaultValue();
}
vmTO.setMetadataManufacturer(metadataManufacturer);
String metadataProduct = VmMetadataProductName.valueIn(vm.getDataCenterId());
if (StringUtils.isBlank(metadataManufacturer)) {
metadataProduct = String.format("CloudStack %s Hypervisor", vm.getHypervisorType().toString());
}
vmTO.setMetadataProductName(metadataProduct);
}
@Override @Override
public void orchestrateStart(final String vmUuid, final Map<VirtualMachineProfile.Param, Object> params, final DeploymentPlan planToDeploy, final DeploymentPlanner planner) public void orchestrateStart(final String vmUuid, final Map<VirtualMachineProfile.Param, Object> params, final DeploymentPlan planToDeploy, final DeploymentPlanner planner)
throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException { throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException {
@ -1259,6 +1272,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
vmGuru.finalizeVirtualMachineProfile(vmProfile, dest, ctx); vmGuru.finalizeVirtualMachineProfile(vmProfile, dest, ctx);
final VirtualMachineTO vmTO = hvGuru.implement(vmProfile); final VirtualMachineTO vmTO = hvGuru.implement(vmProfile);
updateVmMetadataManufacturerAndProduct(vmTO, vm);
checkAndSetEnterSetupMode(vmTO, params); checkAndSetEnterSetupMode(vmTO, params);
@ -4742,7 +4756,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
VmOpLockStateRetry, VmOpWaitInterval, ExecuteInSequence, VmJobCheckInterval, VmJobTimeout, VmJobStateReportInterval, VmOpLockStateRetry, VmOpWaitInterval, ExecuteInSequence, VmJobCheckInterval, VmJobTimeout, VmJobStateReportInterval,
VmConfigDriveLabel, VmConfigDriveOnPrimaryPool, VmConfigDriveForceHostCacheUse, VmConfigDriveUseHostCacheOnUnsupportedPool, VmConfigDriveLabel, VmConfigDriveOnPrimaryPool, VmConfigDriveForceHostCacheUse, VmConfigDriveUseHostCacheOnUnsupportedPool,
HaVmRestartHostUp, ResourceCountRunningVMsonly, AllowExposeHypervisorHostname, AllowExposeHypervisorHostnameAccountLevel, SystemVmRootDiskSize, HaVmRestartHostUp, ResourceCountRunningVMsonly, AllowExposeHypervisorHostname, AllowExposeHypervisorHostnameAccountLevel, SystemVmRootDiskSize,
AllowExposeDomainInMetadata, MetadataCustomCloudName AllowExposeDomainInMetadata, MetadataCustomCloudName, VmMetadataManufacturer, VmMetadataProductName
}; };
} }

View File

@ -37,26 +37,18 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Random; import java.util.Random;
import java.util.UUID;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import com.cloud.agent.api.to.VirtualMachineTO;
import com.cloud.api.query.vo.UserVmJoinVO;
import com.cloud.dc.DataCenterVO;
import com.cloud.dc.dao.DataCenterDao;
import com.cloud.domain.DomainVO;
import com.cloud.domain.dao.DomainDao;
import com.cloud.network.dao.NetworkDao;
import com.cloud.network.dao.NetworkVO;
import com.cloud.network.vpc.VpcVO;
import com.cloud.network.vpc.dao.VpcDao;
import com.cloud.user.AccountVO;
import com.cloud.user.dao.AccountDao;
import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.engine.subsystem.api.storage.StoragePoolAllocator; import org.apache.cloudstack.engine.subsystem.api.storage.StoragePoolAllocator;
import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.framework.config.ScopedConfigStorage;
import org.apache.cloudstack.framework.config.impl.ConfigDepotImpl;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import org.apache.commons.collections.MapUtils; import org.apache.commons.collections.MapUtils;
import org.junit.After;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -76,24 +68,34 @@ import com.cloud.agent.api.Command;
import com.cloud.agent.api.StopAnswer; import com.cloud.agent.api.StopAnswer;
import com.cloud.agent.api.StopCommand; import com.cloud.agent.api.StopCommand;
import com.cloud.agent.api.routing.NetworkElementCommand; import com.cloud.agent.api.routing.NetworkElementCommand;
import com.cloud.agent.api.to.VirtualMachineTO;
import com.cloud.api.query.dao.UserVmJoinDao; import com.cloud.api.query.dao.UserVmJoinDao;
import com.cloud.api.query.vo.UserVmJoinVO;
import com.cloud.dc.ClusterDetailsDao; import com.cloud.dc.ClusterDetailsDao;
import com.cloud.dc.ClusterDetailsVO; import com.cloud.dc.ClusterDetailsVO;
import com.cloud.dc.ClusterVO; import com.cloud.dc.ClusterVO;
import com.cloud.dc.DataCenterVO;
import com.cloud.dc.Pod; import com.cloud.dc.Pod;
import com.cloud.dc.dao.ClusterDao; import com.cloud.dc.dao.ClusterDao;
import com.cloud.dc.dao.DataCenterDao;
import com.cloud.deploy.DataCenterDeployment; import com.cloud.deploy.DataCenterDeployment;
import com.cloud.deploy.DeployDestination; import com.cloud.deploy.DeployDestination;
import com.cloud.deploy.DeploymentPlan; import com.cloud.deploy.DeploymentPlan;
import com.cloud.deploy.DeploymentPlanner; import com.cloud.deploy.DeploymentPlanner;
import com.cloud.deploy.DeploymentPlanner.ExcludeList; import com.cloud.deploy.DeploymentPlanner.ExcludeList;
import com.cloud.deploy.DeploymentPlanningManager; import com.cloud.deploy.DeploymentPlanningManager;
import com.cloud.domain.DomainVO;
import com.cloud.domain.dao.DomainDao;
import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.InvalidParameterValueException;
import com.cloud.host.Host; import com.cloud.host.Host;
import com.cloud.host.HostVO; import com.cloud.host.HostVO;
import com.cloud.host.dao.HostDao; import com.cloud.host.dao.HostDao;
import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.hypervisor.HypervisorGuruManager; import com.cloud.hypervisor.HypervisorGuruManager;
import com.cloud.network.dao.NetworkDao;
import com.cloud.network.dao.NetworkVO;
import com.cloud.network.vpc.VpcVO;
import com.cloud.network.vpc.dao.VpcDao;
import com.cloud.offering.ServiceOffering; import com.cloud.offering.ServiceOffering;
import com.cloud.org.Cluster; import com.cloud.org.Cluster;
import com.cloud.service.ServiceOfferingVO; import com.cloud.service.ServiceOfferingVO;
@ -115,7 +117,9 @@ import com.cloud.storage.dao.VMTemplateZoneDao;
import com.cloud.storage.dao.VolumeDao; import com.cloud.storage.dao.VolumeDao;
import com.cloud.template.VirtualMachineTemplate; import com.cloud.template.VirtualMachineTemplate;
import com.cloud.user.Account; import com.cloud.user.Account;
import com.cloud.user.AccountVO;
import com.cloud.user.User; import com.cloud.user.User;
import com.cloud.user.dao.AccountDao;
import com.cloud.utils.Journal; import com.cloud.utils.Journal;
import com.cloud.utils.Pair; import com.cloud.utils.Pair;
import com.cloud.utils.Ternary; import com.cloud.utils.Ternary;
@ -220,8 +224,12 @@ public class VirtualMachineManagerImplTest {
@Mock @Mock
protected StateMachine2<State, VirtualMachine.Event, VirtualMachine> _stateMachine; protected StateMachine2<State, VirtualMachine.Event, VirtualMachine> _stateMachine;
private ConfigDepotImpl configDepotImpl;
private boolean updatedConfigKeyDepot = false;
@Before @Before
public void setup() { public void setup() {
ReflectionTestUtils.getField(VirtualMachineManager.VmMetadataManufacturer, "s_depot");
virtualMachineManagerImpl.setHostAllocators(new ArrayList<>()); virtualMachineManagerImpl.setHostAllocators(new ArrayList<>());
when(vmInstanceMock.getId()).thenReturn(vmInstanceVoMockId); when(vmInstanceMock.getId()).thenReturn(vmInstanceVoMockId);
@ -251,6 +259,13 @@ public class VirtualMachineManagerImplTest {
virtualMachineManagerImpl.setStoragePoolAllocators(storagePoolAllocators); virtualMachineManagerImpl.setStoragePoolAllocators(storagePoolAllocators);
} }
@After
public void cleanup() {
if (updatedConfigKeyDepot) {
ReflectionTestUtils.setField(VirtualMachineManager.VmMetadataManufacturer, "s_depot", configDepotImpl);
}
}
@Test @Test
public void testaddHostIpToCertDetailsIfConfigAllows() { public void testaddHostIpToCertDetailsIfConfigAllows() {
Host vmHost = mock(Host.class); Host vmHost = mock(Host.class);
@ -1236,4 +1251,48 @@ public class VirtualMachineManagerImplTest {
assertFalse(result.get(1L)); assertFalse(result.get(1L));
assertTrue(result.get(2L)); assertTrue(result.get(2L));
} }
private void overrideVmMetadataConfigValue(final String manufacturer, final String product) {
ConfigKey configKey = VirtualMachineManager.VmMetadataManufacturer;
this.configDepotImpl = (ConfigDepotImpl)ReflectionTestUtils.getField(configKey, "s_depot");
ConfigDepotImpl configDepot = Mockito.mock(ConfigDepotImpl.class);
ScopedConfigStorage storage = Mockito.mock(ScopedConfigStorage.class);
Mockito.when(storage.getConfigValue(Mockito.anyLong(), Mockito.eq(configKey))).thenReturn(manufacturer);
Mockito.when(storage.getConfigValue(Mockito.anyLong(), Mockito.eq(VirtualMachineManager.VmMetadataProductName)))
.thenReturn(product);
Mockito.when(configDepot.findScopedConfigStorage(configKey)).thenReturn(storage);
Mockito.when(configDepot.findScopedConfigStorage(VirtualMachineManager.VmMetadataProductName)).thenReturn(storage);
ReflectionTestUtils.setField(configKey, "s_depot", configDepot);
updatedConfigKeyDepot = true;
}
private Pair<VirtualMachineTO, VMInstanceVO> getDummyVmTOAndVm() {
VirtualMachineTO virtualMachineTO = new VirtualMachineTO(1L, "VM", VirtualMachine.Type.User, 1,
1000, 256, 512, VirtualMachineTemplate.BootloaderType.HVM, "OS",
false, false, "Pass");
VMInstanceVO vm = Mockito.mock(VMInstanceVO.class);
Mockito.when(vm.getDataCenterId()).thenReturn(1L);
return new Pair<>(virtualMachineTO, vm);
}
@Test
public void testUpdateVmMetadataManufacturerAndProductDefaultManufacturer() {
overrideVmMetadataConfigValue("", "");
Pair<VirtualMachineTO, VMInstanceVO> pair = getDummyVmTOAndVm();
VirtualMachineTO to = pair.first();
virtualMachineManagerImpl.updateVmMetadataManufacturerAndProduct(to, pair.second());
Assert.assertEquals(VirtualMachineManager.VmMetadataManufacturer.defaultValue(), to.getMetadataManufacturer());
}
@Test
public void testUpdateVmMetadataManufacturerAndProductCustomManufacturer() {
String manufacturer = UUID.randomUUID().toString();
String product = UUID.randomUUID().toString();
overrideVmMetadataConfigValue(manufacturer, product);
Pair<VirtualMachineTO, VMInstanceVO> pair = getDummyVmTOAndVm();
VirtualMachineTO to = pair.first();
virtualMachineManagerImpl.updateVmMetadataManufacturerAndProduct(to, pair.second());
Assert.assertEquals(manufacturer, to.getMetadataManufacturer());
Assert.assertEquals(product, to.getMetadataProductName());
}
} }

View File

@ -2838,6 +2838,8 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
GuestDef guest = new GuestDef(); GuestDef guest = new GuestDef();
configureGuestAndVMHypervisorType(vmTO, vm, guest); configureGuestAndVMHypervisorType(vmTO, vm, guest);
guest.setManufacturer(vmTO.getMetadataManufacturer());
guest.setProduct(vmTO.getMetadataProductName());
guest.setGuestArch(guestCpuArch != null ? guestCpuArch : vmTO.getArch()); guest.setGuestArch(guestCpuArch != null ? guestCpuArch : vmTO.getArch());
guest.setMachineType(isGuestAarch64() ? VIRT : PC); guest.setMachineType(isGuestAarch64() ? VIRT : PC);
guest.setBootType(GuestDef.BootType.BIOS); guest.setBootType(GuestDef.BootType.BIOS);

View File

@ -95,6 +95,8 @@ public class LibvirtVMDef {
} }
private GuestType _type; private GuestType _type;
private String manufacturer;
private String product;
private BootType _boottype; private BootType _boottype;
private BootMode _bootmode; private BootMode _bootmode;
private String _arch; private String _arch;
@ -124,6 +126,22 @@ public class LibvirtVMDef {
return _type; return _type;
} }
public String getManufacturer() {
return manufacturer;
}
public void setManufacturer(String manufacturer) {
this.manufacturer = manufacturer;
}
public String getProduct() {
return product;
}
public void setProduct(String product) {
this.product = product;
}
public void setNvram(String nvram) { _nvram = nvram; } public void setNvram(String nvram) { _nvram = nvram; }
public void setNvramTemplate(String nvramTemplate) { _nvramTemplate = nvramTemplate; } public void setNvramTemplate(String nvramTemplate) { _nvramTemplate = nvramTemplate; }
@ -182,8 +200,8 @@ public class LibvirtVMDef {
guestDef.append("<sysinfo type='smbios'>\n"); guestDef.append("<sysinfo type='smbios'>\n");
guestDef.append("<system>\n"); guestDef.append("<system>\n");
guestDef.append("<entry name='manufacturer'>Apache Software Foundation</entry>\n"); guestDef.append("<entry name='manufacturer'>" + getManufacturer() +"</entry>\n");
guestDef.append("<entry name='product'>CloudStack " + _type.toString() + " Hypervisor</entry>\n"); guestDef.append("<entry name='product'>" + getProduct() + "</entry>\n");
guestDef.append("<entry name='uuid'>" + _uuid + "</entry>\n"); guestDef.append("<entry name='uuid'>" + _uuid + "</entry>\n");
guestDef.append("</system>\n"); guestDef.append("</system>\n");
guestDef.append("</sysinfo>\n"); guestDef.append("</sysinfo>\n");